How to Disable all BizTalk Hostinstances with PowerShell script - powershell

I'm trying to make a PowerShell script to stop and disable from starting all BizTalk host instances.
Stopping is no problem with this code:
$hosts = Get-WmiObject MSBTS_HostInstance -Namespace 'root/MicrosoftBizTalkServer'
foreach($hostinst in $hosts) {
if ( ($hostinst.ServiceState -ne 1) -and ($hostinst.ServiceState -ne 8) ) {
Write-Host "Stop Hostinstance" $hostinst.HostName
$hostinst.Stop()
Write-Host "Hostinstance" $hostinst.HostName "stopped"
}
}
But now I'm trying to Disable all stopped Host Instances from starting up.
My first try gives no error but doesn't do anything.
All host instance are mentioned in the output but they are not disabled.
$hosts = Get-WmiObject MSBTS_HostInstance -Namespace 'root/MicrosoftBizTalkServer'
foreach($hostinst in $hosts) {
if ( ($hostinst.ServiceState -eq 1) -or ($hostinst.ServiceState -eq 8) ) {
Write-Host "disable Hostinstance" $hostinst.HostName
$hostinst.IsDisabled = $true
Write-Host "Hostinstance" $hostinst.HostName "is disabled"
}
}
My second try gives an error because of the -path parameter.
$hosts = Get-WmiObject MSBTS_HostInstance -namespace 'root/MicrosoftBizTalkServer'
foreach($hostinst in $hosts) {
if ( ($hostinst.ServiceState -eq 1) -or ($hostinst.ServiceState -eq 8) ) {
Write-Host "disable Hostinstance" $hostinst.HostName
Set-ItemProperty -Path $hostinst__PATH -Name IsDisabled -Value $True
# $hostinst.IsDisabled = $true
Write-Host "Hostinstance" $hostinst.HostName "is disabled"
}
}
What is the correct method to set the property IsDisabled to $true or to $false?

BizTalk host instance is a windows service. So you can use powershell's Get-Service cmdlet to stop and disable it.
Suppose your host name is BizTalkServerApplication
Then following script will do the job:
Get-Service -Name BTSSvc`$BizTalkServerApplication | Stop-Service -PassThru | Set-Service -StartupType disabled
Also note the "$" is escaped as "`$"

#Zee is close, but still needs to loop through.. Here's one way to do that - concat the host's name with BTSSvc
$hosts = Get-WmiObject MSBTS_HostInstance -Namespace 'root/MicrosoftBizTalkServer'
foreach($hostinst in $hosts) {
if ( ($hostinst.ServiceState -ne 8) ) { # ignore isolated hosts
$svcName = ('BTSSvc${0}' -f $hostinst.HostName) # get something Get-Service can work with
Get-Service -Name $svcName | Stop-Service -PassThru | Set-Service -StartupType disabled
Write-Host "Hostinstance" $hostinst.HostName "stopped and disabled"
}
}
And if you need to set them back to Automatic/started:
$hosts = Get-WmiObject MSBTS_HostInstance -Namespace 'root/MicrosoftBizTalkServer'
foreach($hostinst in $hosts) {
if ( ($hostinst.ServiceState -ne 8) ) { # ignore isolated hosts
$svcName = ('BTSSvc${0}' -f $hostinst.HostName) # get something Get-Service can work with
Get-Service -Name $svcName | Set-Service -StartupType Automatic -PassThru | Start-Service
Write-Host "Hostinstance" $hostinst.HostName "stopped and disabled"
}
}
And here's a way that might be even a little clearer:
Get-Service | Where-Object { $_.Name.StartsWith("BTSSvc") } | Stop-Service -PassThru | Set-Service -StartupType Disabled

Thanks for your answers.
However there are 2 reasons why this doesn't work completely fine in a BizTalk environment with multiple servers.
First in your solution you have to manually configure the list of servers for each environment in OTAP. With the option Get-WmiObject MSBTS_HostInstance -Namespace 'root/MicrosoftBizTalkServer' BizTalk knows which servers belong the BizTalkGroup.
Second (and more important) the present state is "Automatic(Delayed start)".
Setting the state back to Automatic(Delayed start) with Powershell script is not posible according to several websites.
I understand now why $hostinst.IsDisabled = $true didn't work.
Because the change must be saved first.
That's why I have added a command to save the changes.
$script:btscatalog.SaveChanges() | Out-Null
Unfortunately still nothing seems to be changed.

Do not use default windows service to disable the BizTalk service
Use WMI to get list of BizTalk host instances
$inProcessHosts = "HostType=1"
$nsBTS = "root/MicrosoftBizTalkServer"
$filter = "($inProcessHosts)"
$hostInstances = Get-WmiObject MSBTS_HostInstance -Namespace $nsBTS -Filter $filter
Disable items in a for each loop (redirect output from put)
foreach ($hostInstance in $hostinstances)
{
$hostInstance.IsDisabled = $true
$hostInstance.Put() > $null
}
EDIT:
There is a way to set automatic (delayed start) if needed
#=== Change the startup type for BizTalk services to Automatic (Delayed Start) ===#
get-service BTSSvc* | foreach-object -process { SC.EXE config $_.Name start= delayed-auto}
From Technet WIKI:
https://social.technet.microsoft.com/wiki/contents/articles/19701.biztalk-server-best-practices-create-and-configure-biztalk-server-host-and-host-instances.aspx

Related

I'm trying to run a powershell command to uninstall a WinPcap, but after trying trying different methods I'm still not succesfull?

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 }

Powershell script to compare AD computers to text file and change registry service on those computer and then write the computers that were offline

I'm trying to filter out computers that have already ran the script (that enables remote registry service) within AD from a list in a text file
$NamesFromFile = Get-Content
C:\scripts\Inventory\offlineRemoteRegStartupWorkstations.txt
$computers = get-adcomputer -Filter * | Where-Object {
$_.Name.SubString(1) -in $NamesFromFile }
foreach ($computer in $computers)
{
if (Test-Connection -count 1 -computer $computer.Name -quiet){
Write-Host "Updating system" $computer.Name "....." -ForegroundColor
Green
Set-Service –Name remoteregistry –Computer $computer.Name -StartupType
Automatic
Get-Service remoteregistry -ComputerName $computer.Name | start-service
}
else
{
Write-Host "System Offline " $computer.Name "....." -ForegroundColor Red
echo $computer.Name >> C:\scripts\Inventory\offlineRemoteRegStartup.txt}
}
no errors just blank
Below a re-write of your script.
Because you test if only the first character of the computer name is in the list of computers, your $computers variable will remain empty, so nothing happens.
Also, I think it would be wise to add a check if the startup type of the RemoteRegistry service is not already set to Automatic, because after all.. the computernames you read in from the file may not be accurate.
To avoid having to use $computer.Name all the time, I use a Select-Object -ExpandProperty Name, so we only have to run through a list of strings.
$NamesFromFile = Get-Content -Path 'C:\scripts\Inventory\offlineRemoteRegStartupWorkstations.txt' | Sort-Object -Unique
Get-ADComputer -Filter * |
Where-Object { $NamesFromFile -contains $_.Name } | # if the computer name is in the list
Select-Object -ExpandProperty Name | # we're only interested in the Name property
ForEach-Object {
# the automatic variable '$_' represents a single computername from the list
if (Test-Connection -Count 1 -ComputerName $_ -Quiet) {
# test if the RemoteRegistry service startup type is not already Automatic
# you can do the same with (Get-WmiObject -Class Win32_Service -Filter "Name='RemoteRegistry'" -ComputerName $_)
# only slower..
if ((Get-CimInstance -Class Win32_Service -Filter "Name='RemoteRegistry'" -ComputerName $_).StartMode -ne 'Auto') {
Write-Host "Updating system '$_'....." -ForegroundColor Green
Set-Service –Name RemoteRegistry –Computer $_ -StartupType Automatic
Get-Service -Name RemoteRegistry –Computer $_ | Start-Service
}
else {
Write-Host "RemoteRegistry service startup type already Automatic on computer '$_'....." -ForegroundColor Yellow
}
}
else {
Write-Host "System Offline '$_'....." -ForegroundColor Red
Add-Content -Path 'C:\scripts\Inventory\offlineRemoteRegStartup.txt' -Value $_
}
}

Is There a function to bypass dependent services when stoping a service in Powershell?

I have some issues with my Powershell code
I need to stop and disable some services with this script BUT there are some issues, here it is:
Get-Content -path $PWD\servicestop1.txt | ForEach-Object
{
$service = $_
(Set-Service -Name $service -Status Stopped -StartupType Disabled -PassThru )
}
1 - I encounter some dependencies issue when I want to stop some services
2 - I can't get to disable and stop them in the same script
Do you have any idea?
Thanks a lot!
PS: I tried to use the parameter "-force" but it didn't work
Without knowing the servicestop1.txt actually holds valid service names, You may try this:
Get-Content -Path "$PWD\servicestop1.txt" | ForEach-Object {
$service = Get-Service -Name $_ -ErrorAction SilentlyContinue
if ($service) {
if ($service.Status -eq 'Running') {
# stop the service and wait for it
$service | Stop-Service -Force
}
if ($service.StartType -ne 'Disabled') {
$service | Set-Service -StartupType Disabled
}
}
else {
Write-Warning "Could not find service with name '$_'"
}
}

powershell code that first checks the service on server and displays server name service name and boot type

how can i write a powershell code that first checks the service on server and displays server name service name and boot type! then if it is on automatic, it switches manually and efer it shows the status again
$servicename = 'spooler'
$server = 'server2'
$G$GetStatus= Get-Service -DisplayName $servicename -ComputerName $server | Select-Object -ExpandProperty StartType
Write-host "$GetStatus" -ForegroundColor red
Write-host "$servicename på $server" -ForegroundColor Green
if ($GetStatus.StartType -eq 'Automatic') {
$GetStatus | Set-Service -StartupType Manual
}
}
}
Write-output "$GetStatus" -ForegroundColor red
Write-output "$servicename på $server" -ForegroundColor Green
here's an example of what i mean by NOT throwing out the object in favor of one value from one property of the object.
$servicename = 'spooler'
$server = 'LocalHost'
$ServiceInfo = Get-Service -Name $servicename -ComputerName $server
Write-host $ServiceInfo.StartType -ForegroundColor red
Write-host "$servicename på $server" -ForegroundColor Green
''
if ($ServiceInfo.StartType -eq 'Automatic')
{
$ServiceInfo |
Set-Service -StartupType Manual -WhatIf
}
''
Write-output $ServiceInfo.StartType
Write-output "$servicename på $server"
output ...
Automatic
spooler på LocalHost
What if: Performing the operation "Set-Service" on target "Print Spooler (spooler)".
Automatic
spooler på LocalHost
i have not tested it on my system, but the -WhatIf seems to indicate it will work. i have only the one system to use ... and am unwilling to muck around with it. [grin]
notes ...
kept the entire object instead of only the value of the StartType property
addressed the desired property by its name $ServiceInfo.StartType
used the entire object to tell Set-Service what to work on
This should do what you want:
$serviceName = "spooler"
$server = "server2"
Get-Service -Name $serviceName -ComputerName $server |
ForEach-Object {}{
$_ | Format-Table Name, Status, StartType -AutoSize
if ($_.StartType -eq "Automatic")
{
Set-Service -InputObject $_ -StartupType Manual
}
}{Get-Service -Name $serviceName -ComputerName $server | Format-Table Name, Status, StartType -AutoSize}
I would probably do something like this:
$server = 'server2'
$servicename = 'spooler'
$services = Get-Service -ComputerName $server -Name $servicename
# show what was found
Write-Host "`r`nService(s) named '$servicename' on '$server'" -ForegroundColor Yellow
$services | Format-Table DisplayName, Name, ServiceName, Status, StartType, MachineName -AutoSize
# next change the StartupType for any service found that is set to 'Automatic'
$services | Where-Object { $_.StartType -eq 'Automatic' } | ForEach-Object {
Write-Host "Setting StartupType for service '$($_.Name)' on computer '$($_.MachineName)' to 'Manual'" -ForegroundColor Green
$_ | Set-Service -StartupType Manual }
# show what has changed
Get-Service -ComputerName $server -Name $servicename |
Format-Table DisplayName, Name, ServiceName, Status, StartType, MachineName -AutoSize
If you do not know the exact name of the service, you may better use Get-Service with a partial name.
You can do this with the like operator. In that case, add asterikses around the servicename and
change the lines $services = Get-Service -ComputerName $server -Name $servicename so it becomes:
$servicename = '*spooler*'
$services = Get-Service -ComputerName $server | Where-Object { $_.Name -like $servicename }

Check if a Windows service exists and delete in PowerShell

I am currently writing a deployment script that installs a number of Windows services.
The services names are versioned, so I want to delete the prior Windows service version as part of the installs of the new service.
How can I best do this in PowerShell?
You can use WMI or other tools for this since there is no Remove-Service cmdlet until Powershell 6.0 (See Remove-Service doc)
For example:
$service = Get-WmiObject -Class Win32_Service -Filter "Name='servicename'"
$service.delete()
Or with the sc.exe tool:
sc.exe delete ServiceName
Finally, if you do have access to PowerShell 6.0:
Remove-Service -Name ServiceName
There's no harm in using the right tool for the job, I find usign sc.exe (via PowerShell) to be the most reliable method with few dependencies.
Local:
sc.exe delete "MyService"
Remote server:
sc.exe \\server delete "MyService"
If you just want to check service existence:
if (Get-Service "My Service" -ErrorAction SilentlyContinue)
{
"service exists"
}
I used the "-ErrorAction SilentlyContinue" solution but then later ran into the problem that it leaves an ErrorRecord behind. So here's another solution to just checking if the Service exists using "Get-Service".
# Determines if a Service exists with a name as defined in $ServiceName.
# Returns a boolean $True or $False.
Function ServiceExists([string] $ServiceName) {
[bool] $Return = $False
# If you use just "Get-Service $ServiceName", it will return an error if
# the service didn't exist. Trick Get-Service to return an array of
# Services, but only if the name exactly matches the $ServiceName.
# This way you can test if the array is emply.
if ( Get-Service "$ServiceName*" -Include $ServiceName ) {
$Return = $True
}
Return $Return
}
[bool] $thisServiceExists = ServiceExists "A Service Name"
$thisServiceExists
But ravikanth has the best solution since the Get-WmiObject will not throw an error if the Service didn't exist. So I settled on using:
Function ServiceExists([string] $ServiceName) {
[bool] $Return = $False
if ( Get-WmiObject -Class Win32_Service -Filter "Name='$ServiceName'" ) {
$Return = $True
}
Return $Return
}
So to offer a more complete solution:
# Deletes a Service with a name as defined in $ServiceName.
# Returns a boolean $True or $False. $True if the Service didn't exist or was
# successfully deleted after execution.
Function DeleteService([string] $ServiceName) {
[bool] $Return = $False
$Service = Get-WmiObject -Class Win32_Service -Filter "Name='$ServiceName'"
if ( $Service ) {
$Service.Delete()
if ( -Not ( ServiceExists $ServiceName ) ) {
$Return = $True
}
} else {
$Return = $True
}
Return $Return
}
More recent versions of PS have Remove-WmiObject. Beware of silent fails for $service.delete() ...
PS D:\> $s3=Get-WmiObject -Class Win32_Service -Filter "Name='TSATSvrSvc03'"
PS D:\> $s3.delete()
...
ReturnValue : 2
...
PS D:\> $?
True
PS D:\> $LASTEXITCODE
0
PS D:\> $result=$s3.delete()
PS D:\> $result.ReturnValue
2
PS D:\> Remove-WmiObject -InputObject $s3
Remove-WmiObject : Access denied
At line:1 char:1
+ Remove-WmiObject -InputObject $s3
+ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ CategoryInfo : InvalidOperation: (:) [Remove-WmiObject], ManagementException
+ FullyQualifiedErrorId : RemoveWMIManagementException,Microsoft.PowerShell.Commands.RemoveWmiObject
PS D:\>
For my situation I needed to be running 'As Administrator'
To delete multiple services in Powershell 5.0, since remove service does not exist in this version
Run the below command
Get-Service -Displayname "*ServiceName*" | ForEach-object{ cmd /c sc delete $_.Name}
One could use Where-Object
if ((Get-Service | Where-Object {$_.Name -eq $serviceName}).length -eq 1) {
"Service Exists"
}
Combining Dmitri & dcx's answers I made this:
function Confirm-WindowsServiceExists($name)
{
if (Get-Service $name -ErrorAction SilentlyContinue)
{
return $true
}
return $false
}
function Remove-WindowsServiceIfItExists($name)
{
$exists = Confirm-WindowsServiceExists $name
if ($exists)
{
sc.exe \\server delete $name
}
}
For single PC:
if (Get-Service "service_name" -ErrorAction 'SilentlyContinue'){(Get-WmiObject -Class Win32_Service -filter "Name='service_name'").delete()}
else{write-host "No service found."}
Macro for list of PCs:
$name = "service_name"
$list = get-content list.txt
foreach ($server in $list) {
if (Get-Service "service_name" -computername $server -ErrorAction 'SilentlyContinue'){
(Get-WmiObject -Class Win32_Service -filter "Name='service_name'" -ComputerName $server).delete()}
else{write-host "No service $name found on $server."}
}
To check if a Windows service named MySuperServiceVersion1 exists, even when you might not be sure of its exact name, you could employ a wildcard, using a substring like so:
if (Get-Service -Name "*SuperService*" -ErrorAction SilentlyContinue)
{
# do something
}
PowerShell Core (v6+) now has a Remove-Service cmdlet.
I don't know about plans to back-port it to Windows PowerShell, where it is not available as of v5.1.
Example:
# PowerShell *Core* only (v6+)
Remove-Service someservice
Note that invocation fails if the service doesn't exist, so to only remove it if it currently exists, you could do:
# PowerShell *Core* only (v6+)
$name = 'someservice'
if (Get-Service $name -ErrorAction Ignore) {
Remove-Service $name
}
Adapted this to take an input list of servers, specify a hostname and give some helpful output
$name = "<ServiceName>"
$servers = Get-content servers.txt
function Confirm-WindowsServiceExists($name)
{
if (Get-Service -Name $name -Computername $server -ErrorAction Continue)
{
Write-Host "$name Exists on $server"
return $true
}
Write-Host "$name does not exist on $server"
return $false
}
function Remove-WindowsServiceIfItExists($name)
{
$exists = Confirm-WindowsServiceExists $name
if ($exists)
{
Write-host "Removing Service $name from $server"
sc.exe \\$server delete $name
}
}
ForEach ($server in $servers) {Remove-WindowsServiceIfItExists($name)}
For PowerShell versions prior to v6, you can do this:
Stop-Service 'YourServiceName'; Get-CimInstance -ClassName Win32_Service -Filter "Name='YourServiceName'" | Remove-CimInstance
For v6+, you can use the Remove-Service cmdlet.
Observe that starting in Windows PowerShell 3.0, the cmdlet Get-WmiObject has been superseded by Get-CimInstance.
Windows Powershell 6 will have Remove-Service cmdlet.
As of now the Github release shows PS v6 beta-9
Source: https://learn.microsoft.com/en-us/powershell/module/microsoft.powershell.management/remove-service?view=powershell-6
I know it's an old question but if someone is looking for one-liner:
On PS Version > 7.2
Wildcard search on the Name property
Get-Service *name* | Select-Object -First 1 | Remove-Service
Search the Display Name property
Get-Service -DisplayName "My Service Description" | Remove-Service