Run SQL Server PowerShell Cmdlets as a Different User

One of the ways I practice the principal of least privilege is by logging into my computer as a domain user who is also a standard local user. I typically run PowerShell as a domain user who is a local admin and elevate on a per command basis using a domain account with more access only when absolutely necessary. The problem I've run into is neither the account I'm logged into my computer as or the one I'm running PowerShell as has the ability to execute SQL queries that I need to run against various SQL servers in my environment.

I've installed both the SQLServer and BetterCredentials PowerShell modules from the PowerShell Gallery which are used thoughout this blog article. Windows PowerShell version 5.0 or higher (which ships by default with Windows 10) is required to run some of the commands shown in this blog article.

1Install-Module -Name SqlServer, BetterCredentials -AllowClobber

I don't want to run PowerShell with elevated domain credentials . Unless I'm missing something, the Credential parameter for all of the various SQL cmdlets seems to want SQL authentication credentials, not Windows authentication ones.

At first, I tried kicking off another PowerShell process from within PowerShell as an elevated user to run the SQL commands from. The problem is the process started, ran, returned the results, and exited when completed.

1Start-Process -FilePath "$env:windir\System32\WindowsPowerShell\v1.0\powershell.exe" -ArgumentList "
2    Invoke-Sqlcmd -ServerInstance sql16 -Database master -Query '
3        select * from sys.databases'
4" -Credential (Get-Credential -UserName mikefrobbins\administrator -Store)

sql-alt-user1a.jpg

Start-Process also has a Wait parameter so I tried it to see if it would cause the PowerShell process that's spawned to wait until it was manually closed. No such luck as it also exited automatically when completed.

1Start-Process -FilePath "$env:windir\System32\WindowsPowerShell\v1.0\powershell.exe" -ArgumentList "
2    Invoke-Sqlcmd -ServerInstance sql16 -Database master -Query '
3        select * from sys.databases'
4" -Credential (Get-Credential -UserName mikefrobbins\administrator -Store) -Wait

sql-alt-user2a.jpg

The only way to make this option work is to pipe the results to Out-GridView with its Wait parameter. This keeps the spawned PowerShell process open along with the grid view window until it's manually closed.

1Start-Process -FilePath "$env:windir\System32\WindowsPowerShell\v1.0\powershell.exe" -ArgumentList "
2    Invoke-Sqlcmd -ServerInstance sql16 -Database master -Query '
3        select * from sys.databases' |
4    Out-GridView -Wait
5" -Credential (Get-Credential -UserName mikefrobbins\administrator -Store)

sql-alt-user3a.jpg

A better option is to simply run the command as a PowerShell job using the Start-Job cmdlet since Invoke-Sqlcmd doesn't have an AsJob parameter.

1Start-Job -ScriptBlock {
2    Invoke-Sqlcmd -ServerInstance sql16 -Database master -Query '
3    select * from sys.databases'
4} -Credential (Get-Credential -UserName mikefrobbins\administrator -Store)

sql-alt-user4a.jpg

Get-Job is used to determine the state of the job. As you can see in the following results, the job has completed.

1Get-Job -Name Job1

sql-alt-user5a.jpg

Receive-Job is used to return the results of the job. Note, the first time the Keep parameter is not specified, the results will be removed from the job.

1Get-Job -Name Job1 | Receive-Job -Keep | Format-Table

sql-alt-user6a.jpg

Remove-Job is used to remove the actual job.

1Get-Job -Name Job1 | Remove-Job

sql-alt-user7a.jpg

If there's a different way to accomplish this task, I'd love to hear about it via a comment to this blog article.

µ