SQL Server Service Account Change using Powershell - powershell

I have prepared below script to change sql server service account. But the service is not stopping and starting when i run below script. Any diea? is there any beeter way to do this. is there any alternative for Sleep. We don't know how much service takes to stop and start. Is there a way to keep powershell to wait until service completely
stops/starts.
$Services = Get-WmiObject Win32_Service -ComputerName "." | Where { $_.name -eq 'MSSQLSERVER' }
ForEach($Service in $Services)
{
$StopStatus = $Service.StopService()
Sleep 15
If ($StopStatus.ReturnValue -eq "0")
{write-host "$Service -> Service Stopped Successfully"}
$ChangeStatus = $Service.change($null,$null,$null,$null,$null,$null,$ServiceAccount,$Password,$null,$null,$null)
If ($ChangeStatus.ReturnValue -eq "0")
{write-host "$Service -> Sucessfully Changed Service Account"}
$StartStatus = $Service.StartService()
Sleep 25
If ($ChangeStatus.ReturnValue -eq "0")
{write-host "$Service -> Service Started Successfully"}
}

You can see if the service is stopped ( or started ) in a loop and then proceed:
$sleepCounter = 1
While((Get-Service $serviceName).status -ne "Stopped" ){
Write-Host "Waiting for service to stop. Attempt $sleepCounter of 20"
sleep 1
if($sleepCounter -eq 20) { break }
$sleepCounter++
}
Also, you can do the following to get the service instead of using where-object
$svc=gwmi win32_service -filter "name='$serviceName'"

Related

Powershell script to checking services on multiple remote machines and to start them if they are not running

New to Powershell, My goal is to go through a list of remote Computers and check to see if certain services are running on them and starting the services if they are not. what would be the best approach in creating a variable for the services on said servers?
Server1.txt - 'ServiceA ServiceB ServiceC'
Server2.txt - 'ServiceD ServiceE ServiceF'
Server3.txt - 'ServiceG ServiceH'
$services = get-content .\Server1.txt
$services | ForEach {
try {
Write-Host "Attempting to start '$($.DisplayName)'"
Start-Service -Name $.Name -ErrorAction STOP
Write-Host "SUCCESS: '$($.DisplayName)' has been started"
} catch {
Write-output "FAILED to start $($.DisplayName)"
}
}
Thank you.
In your input, you have mentioned one text file for each server which is not advisable. Also there is no computer name in your Start-service Command. Please find my input sample below.
server1-serviceA,ServiceB,ServiceC
server2-serviceD,ServiceE,ServiceF
server3-serviceG,ServiceH,ServiceI
And here is the powershell script, since you have mentioned different services for each server there is a need for using split function.
$textFile = Get-Content C:\temp\servers.txt
foreach ($line in $textFile) {
$computerName = $line.split("-")[0] #Getting computername by using Split
$serviceNames = $line.split("-")[1] #Getting Service names by using split
foreach ($serviceName in $serviceNames.split(",")) {
# Again using split to handle multiple service names
try {
Write-Host " Trying to start $serviceName in $computerName"
Get-Service -ComputerName $computerName -Name $serviceName | Start-Service -ErrorAction Stop
Write-Host "SUCCESS: $serviceName has been started"
}
catch {
Write-Host "Failed to start $serviceName in $computerName"
}
}
}
I haven't tested the script for starting the service, but the loop works properly for multiple servers and their respective services. Thanks!

How to ensure IIS website is completely stopped in Powershell?

I've got a Powershell script that stops an IIS website and corresponding app pool and then deletes the app logs (log4net logs). Here is the script snippet:
stop-website -name "MyWebsite"
stop-webapppool -name "MyWebsite"
del c:\inetpub\MyWebsite\logs\*.*
The problem is stop-website and stop-webapppool seem to return before the website is completely shutdown which results in the delete failing saying the file is being used by another process:
del : Cannot remove item C:\inetpub\MyWebsite\logs\App.log: The process cannot access the file 'C:\inetpub\MyWebsite\logs\App.log' because it is being used by another process.
If I add a 10 second sleep between the stop commands and the del command then the logs are deleted successfully. This is very hackish though and not reliable. Is there a way to force the stop-website/stop-webapppool commands to not return until the website/apppool is completely stopped?
Thanks.
Implemented solution from the below link. I will wait ~60 seconds and then kill the IIS process if it hasn't stopped.
https://greenfinch.ie/blog/powershellscript.html
"Stopping IIS site [$name]" >> $logFile
stop-website -name $name
"Stopping app pool [$name]" >> $logFile
stop-webapppool -name $name
$sleepTime = 5
$processId = $TRUE
while ($processId)
{
$processId = Get-WmiObject -Class win32_process -filter "name='w3wp.exe'" |
?{ ($_.CommandLine).Split("`"")[1] -eq $name } |
%{ $_.ProcessId }
if ($sleepTime -gt 60)
{
"Waited [$sleepTime] sec for process [$processId] to stop and it is still running. Killing it." >> $logFile
Stop-Process $processId
break
}
if ($processId)
{
"App pool [$name] is running with process ID: [$processId]. Sleeping for [$sleepTime] sec and then checking again." >> $logFile
Start-Sleep -s $sleepTime
$sleepTime = $sleepTime + 10
}
}
You can use these two commands to check the status of the website/app, say after 10 seconds, then use an If statement to delete logs only when the status returned is stopped
Get-WebsiteState -name "MyWebsite"
Get-WebAppPoolState -name "MyWebsite"
This loop should help you too
$currentRetry = 0;
$success = $false;
do{
$status = Get-WebAppPoolState -name "MyWebsite"
if ($status -eq "Stopped"){
<....your code here....>
$success = $true;
}
Start-Sleep -s 10
$currentRetry = $currentRetry + 1;
}
while (!$success -and $currentRetry -le 4)
Updated Apr 24, 2019
Based on comment and current cmdlet document, it appears the return type is indeed an object. Thus presumably can be handled as commented or the line snippet below. Author no longer have access to Windows Server environment therefore did not directly modify original answer nor able to test the update
if ($status.Value -eq "Stopped")
After you run 'Stop-WebAppPool' the state of the WebAppPool will be "Stopping" and it may take a few seconds before the state of the WebAppPool is actually "Stopped".
Here is a little function to help with the WebAppPoolState
function Stop-AppPool ($webAppPoolName,[int]$secs) {
$retvalue = $false
$wsec = (get-date).AddSeconds($secs)
Stop-WebAppPool -Name $webAppPoolName
Write-Output "$(Get-Date) waiting up to $secs seconds for the WebAppPool '$webAppPoolName' to stop"
$poolNotStopped = $true
while (((get-date) -lt $wsec) -and $poolNotStopped) {
$pstate = Get-WebAppPoolState -Name $webAppPoolName
if ($pstate.Value -eq "Stopped") {
Write-Output "$(Get-Date): WebAppPool '$webAppPoolName' is stopped"
$poolNotStopped = $false
$retvalue = $true
}
}
return $retvalue
}
you can run this function using e.g.
Stop-AppPool "MyWebsite" 30
and check the return-value to see if the WebAppPool has stopped within the given seconds
The simplest way to stop the app pool and get it into Stopped state is to use appcmd.exe. It will return when the app pool is really stopped or you'll get an error
Just do this on PowerShell:
& $env:windir\system32\inetsrv\appcmd.exe stop apppool /apppool.name:"YourAppPoolName"
When your AppPool is correctly stooped you'll get this message:
"YourAppPoolName" successfully stopped
I fix the #user4531 code It would be failed if the app pool is stopped before :
function Stop-AppPool ($webAppPoolName,[int]$secs) {
$retvalue = $false
$wsec = (get-date).AddSeconds($secs)
$pstate = Get-WebAppPoolState -Name $webAppPoolName
if($pstate.Value -eq "Stopped") {
Write-Output "WebAppPool '$webAppPoolName' is stopped already"
return $true
}
Stop-WebAppPool -Name $webAppPoolName
Write-Output "$(Get-Date) waiting up to $secs seconds for the WebAppPool '$webAppPoolName' to stop"
$poolNotStopped = $true
while (((get-date) -lt $wsec) -and $poolNotStopped) {
$pstate = Get-WebAppPoolState -Name $webAppPoolName
if ($pstate.Value -eq "Stopped") {
Write-Output "WebAppPool '$webAppPoolName' is stopped"
$poolNotStopped = $false
$retvalue = $true
}
}
return $retvalue
}
It can use like this :
Stop-AppPool "SSO" 30
Here is how I did it with Get-IISServerManager.
$manager = Get-IISServerManager
$site = $manager.Sites["mySiteName"]
if($site.State -ne "Stopped") {
$site.Stop()
}
while ($site.State -ne "Stopped") {
"waiting 1 second for site to stop..."
Start-Sleep -s 1
}
"site stopped"

PowerShell won't display my code

I am fairly new to PowerShell and I am wondering why when I run this code it skips everything and then goes straight to the pause?
Once I hit enter it does not display anything and closes the window.
To better explain what I am doing here. I am trying to connect remotely to a server in our network and check to see if specific processes are running. If they are not running the script will make them run.
Any idea what I could be doing wrong in PowerShell v3 on Windows 7 64bit?
$recall = Get-WmiObject win32_service -computername srv-95-obweb | Where {$_.name -eq 'Hyland Sch4'}
$sleeplab = Get-WmiObject win32_service -computername srv-95-obweb | Where {$_.name -eq 'Hyland Sch3'}
$date = Get-Date
if($recall.Status -eq 'Stopped') {
Write-Host "Recall service is currently stopped and will be automatically started"
Get-Service '*Sch4' | Start-Service
Write-Host "Recall service has been started $date"
} Else {
if($recall.Status -eq 'Running') {
Write-Host "Recall service is currently running"
}
}
if($sleeplab.Status -eq 'Stopped') {
Write-Host "Sleep Lab service is currently stopped and will be automatically started"
Get-Service '*Sch3' | Start-Service
Write-Host "Sleep Lab service has been started $date"
} Else {
if($sleeplab.Status -eq 'Running') {
Write-Host "Sleep Lab service is currently running"
}
}
pause
The second if caused it to be false so it didnt post. Also had the wrong propertie. Making it .State instead of .status resolved the issue. Thanks all for your help

Powershell security get-service different results interactive vs scheduled-task

I've spent hours trying to pin down this problem. I'm running a PowerShell to verify if various services are running. I want to run it every 5 minutes from Windows Task Scheduler.
It checks services on other servers, and some on the same machine on which it is running. When I run it under task scheduler, under the same userid that I'm running interactive I get different results. Interactively, shows all the services on local machine are running. When run through task scheduler, it tells me that service is not found.
This is just a fragment of a larger program. I get the server/service names from a CSV file, then at the end it sends a nice HTML email. I added the Add-Content to create a trace file to prove this happening.
foreach ($line in $csv) {
$reportStatus = ""
$ServerCount = $ServerCount + 1
#$Service = (get-service -Name $line.ServiceName -ComputerName $line.ServerName)
#this is slower than above, but it gives us the processId which we can use to find out what time the service/process started
write-host "Verifying: " $line.ServerName $line.ServiceName
$myDate = Get-Date
Add-Content D:\scripts\ServiceMonitorTrace.txt "$myDate $($line.ServerName) $($line.ServiceName)"
$Service = (get-wmiobject win32_service -ComputerName $line.ServerName -filter "name = '$($line.ServiceName)'")
if ($Service -eq $null)
{
$reportStatus = "Service Not Found: name = '$($line.ServiceName)'"
$trColor = "Yellow"
$ErrorCount = $ErrorCount + 1
$CriticalErrorCount = $CriticalErrorCount + 1
$CreationDate = "NA"
Write-Host "----> $reportStatus "
Add-Content D:\scripts\ServiceMonitorTrace.txt "$myDate $reportStatus"
}
}
New Simpler Version (has exact same issue):
$Service = (get-wmiobject win32_service -ComputerName "DAL-BIZ-APP01" -filter "name = 'LanManServer'")
if ($Service -eq $null)
{
$reportStatus = "Service not found"
}
else
{
$reportStatus = "Service found"
}
$myDate = Get-Date
Write-Host $reportStatus
Add-Content D:\scripts\ServiceTestTrace.txt "$myDate $reportStatus"
Interactive Results:
10/31/2013 09:34:00 DAL-BIZ-APP01 MSDTC
10/31/2013 09:34:00 DAL-BIZ-APP01 BTSSvc$BizTalkHost_QT_Default
Scheduled Job Results:
10/31/2013 09:25:42 DAL-BIZ-APP01 MSDTC
10/31/2013 09:25:42 Service Not Found: name = 'MSDTC'
10/31/2013 09:25:42 DAL-BIZ-APP01 BTSSvc$BizTalkHost_QT_Default
I run it from a command file that contains this:
powershell -command "& 'D:\Scripts\ServerMonitor.ps1'" d:\Scripts\ServerMonitorConfig.csv
Running the command file from a non-admin command prompt window or the scheduler also seems to have different results.
New Simpler Version if someone want to try, just substitute two computer names:
$Service = (get-wmiobject win32_service -ComputerName "DAL-BIZ-APP01" -filter "name = 'LanManServer'")
if ($Service -eq $null)
{
$reportStatus = "Service not found"
}
else
{
$reportStatus = "Service found"
}
$myDate = Get-Date
Write-Host $reportStatus
Add-Content D:\scripts\ServiceTestTrace.txt "$myDate DAL-BIZ-APP01 $reportStatus"
$Service = (get-wmiobject win32_service -ComputerName "DAL-BIZ-APP02" -filter "name = 'LanManServer'")
if ($Service -eq $null)
{
$reportStatus = "Service not found"
}
else
{
$reportStatus = "Service found"
}
$myDate = Get-Date
Write-Host $reportStatus
Add-Content D:\scripts\ServiceTestTrace.txt "$myDate DAL-BIZ-APP02 $reportStatus"
Results:
10/31/2013 16:07:48 DAL-BIZ-APP01 Service found
10/31/2013 16:07:48 DAL-BIZ-APP02 Service found
10/31/2013 16:08:03 DAL-BIZ-APP01 Service not found
10/31/2013 16:08:03 DAL-BIZ-APP02 Service found
16:07:48 was from command prompt, 16:08:03 was from task scheduler.
I added this to code:
if ($error -ne $null)
{
Write-Host "----> $($error[0].Exception) "
Add-Content $TraceFilename "$myDate TRCE1 $($error[0].Exception)"
}
Now I'm able to see the reason that was getting swallowed:
11/13/2013 11:35:37 TRCE1 System.Management.ManagementException:
Access denied at System.Management.ManagementException.ThrowWithExtendedInfo(ManagementStatus
errorCode) at
System.Management.ManagementObjectCollection.ManagementObjectEnumerator.MoveNext()
at Microsoft.PowerShell.Commands.GetWmiObjectCommand.BeginProcessing()
I have not yet figured out the "Access Denied", but at least I'm happy I see the true error now, i.e. the reason the result of "get-wmiobject win32_service..." was null.
I'm following up with the "Access Denied" in a new thread here:
Access Denied - get-wmiobject win32_service (Powershell)

PowerShell, BizTalk and changing Host Instance configuration

Yet another PowerShell/BizTalk question, but first some background:
We have a lot of (8 inprocess, 2 isolated) Host Instances on one developer environment. One of the instances has gone corrupt ("Installation Failed" as status in Admin Console). I saw that it was lacking password and tried to update it manually. No luck, the password I had was wrong and it was also the same password stored for the account in our CMDB... Oh, well. Just to reset it and change it on all host instances.
Well, I wanted to try out to do it the PowerShell way. It kind of works, but only if the instances is in ServiceState 8? ServiceState 4 (started) of course gives an error. But so does ServiceState 1 (stopped)?
Very annoying. It is the method Install that fails:
Exception calling "Install" : "A failure occurred while installing the Windows NT
service BTSSvc$Test_host.
Please verify the following:
1) The credentials supplied are correct and the specified user name has the "log
on as service" privilege enabled.
2) All Microsoft Management Console (MMC) Service windows are closed. The Window
s Service Control Manager will not allow the creation of a service if the service
has been deleted but is still referenced by an open MMC window. "
Code:
$hosts = Get-WmiObject MSBTS_HostInstance -namespace 'root/MicrosoftBizTalkServer'
foreach($hostinst in $hosts)
{
if ($hostinst.Logon -eq $acc)
{
if($hostinst.ServiceState -eq 1 -or 8)
{
write-host "Hostinstans" $hostinst.HostName "har ServiceState" $hostinst.ServiceState
$hostinst.Install($acc, $pw, "True")
Start-Sleep -Seconds 30
write-host "Hostinstans" $hostinst.HostName "har nytt lösenord och ServiceState" $hostinst.ServiceState
}
}
}
Anyone got ideas? It is annoying the cr*p out of me!
Best regards,
Joakim
$hostinst.ServiceState -eq 1 -or 8
should be rewritten
($hostinst.ServiceState -eq 1) -or ($hostinst.ServiceState -eq 8)
Try out in your PowerShell console:
3 -eq 1 -or 8
Found the answer!
If the instance is in ServiceState 1 I have to uninstall it before making any changes to it! My code for this should be like this (for example):
$hosts = Get-WmiObject MSBTS_HostInstance -namespace 'root/MicrosoftBizTalkServer'
foreach($hostinst in $hosts)
{
if ($hostinst.Logon -eq $acc)
{
if(($hostinst.ServiceState -eq 1) -or ($hostinst.ServiceState -eq 8))
{
if($hostinst.ServiceState -eq 1)
{
$hostinst.Uninstall()
}
write-host "Hostinstans" $hostinst.HostName "har ServiceState" $hostinst.ServiceState
$hostinst.Install($acc, $pw, "True")
Start-Sleep -Seconds 30
write-host "Hostinstans" $hostinst.HostName "har nytt lösenord och ServiceState" $hostinst.ServiceState
}
}
}