I want to remotely stop / start / restart SQlBrowser service from a .net core 6 application running on IIS that uses the Powershell 7 library.
The application pool of the .net core service runs under a domain user, called domain.local\service-mgr-svc.
If I make domain.local\service-mgr-svc local administrator on the remote SQL Server, that I want to control the sqlbrowser service on, the remote invoke command works:
Invoke-Command -ComputerName sql-svr.domain.local -Scriptblock { restart-service -Name "sqlbrowser" }
When I take the user out of local administrator group, I get the following error
Cannot find any service with the service name "SQL Browser"
If I try just "get-service", I get response about "might need elevated permissions"
My question is, what are those permissions? I've been down the rabbit-hole on this.
What I have tried:
GPO to give the user on the remote server;
Giving the user the following permissions on the Root Namespace in the WMI config;
Alas, it does not work. What can I try next?
(Posting the solution on behalf of the question author in order to move it to the answer space).
So I had a look at this SubInACL.exe stuff and that did the job!
I noticed that running cmd on the remote server and trying to stop / start SQLBrowser, I got access denied.
So did a
dir>.\SubInACL.exe /service SQLBrowser /grant=domain\user=PTOIS
And it works!
Further update: to automate this into a .ps1 startup script, I actually ended up using sc.exe. Its a bit tricky as you need to persist the current value and append your required SID and permissions SDDL. So I did the below, where the $default_svc_sddl is the current SDDL of a given service, and the $util_sddl is the SDDL of the user + permissions that I wanted to add.
# Give utilityrunner-svc SQLBrowser service permissions
$SQLServices= "SQLBrowser"
foreach ($service in $SQLServices) {
$this_svc_sddl = sc.exe sdshow $service
if ($this_svc_sddl -eq $default_svc_sddl ) {
$sddl_string = [regex]::Split($this_svc_sddl, 'S:')
$split_sddl_string = $sddl_string[0]
$new_sddl = $split_sddl_string+$util_sddl
sc.exe sdset $service $new_sddl
} else {
write-host "Permission for utilityrunner-svc already set for $service"
}
}
# Give utilityrunner-svc ServiceControlManager permissions
$scm="SCManager"
$scm_sddl = sc.exe sdshow $scm
if ( scm_sddl -eq $default_scm_sddl ) {
$scm_sddl_string = [regex]::Split($scm_sddl, 'S:')
$split_scm_sddl_string = $scm_sddl_string[0]
$new_scm_sddl = $split_scm_sddl_string+$util_sddl
sc.exe sdset $scm $new_scm_sddl
} else {
write-host "$scm - Permission for utilityrunner-svc already set."
}
Found also needed SCManager permissions also, hence the permissions changes for that.
I realise the logic isn't completely solid here, in that, if the default_svc_sddl doesn't match and the user isn't permissioned, it wont run, but it works for us.
You could probably do something a bit more advanced using "ConvertFrom-SddlString" cmdlet in PS to query all the SDDLs against a service and accurately determine whether or not that the user in question, "domain.local\utilityrunner-svc" in my instance, has permissions applied or not.