Jack McCauley
Jack McCauley

Reputation: 45

Managing Windows Services with Remote powershell - Windows Server 2019 Datacenter Edition

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?

Upvotes: 0

Views: 162

Answers (1)

halfer
halfer

Reputation: 20439

(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.

Upvotes: 0

Related Questions