Launch Elevated CMD.exe from Powershell - powershell

I am trying to launch an elevated CMD window from PowerShell but I am running into some issues. Below is the Code I have now. There is an admin account on the machine that has the username of "test" and a Password of "test"
$username = "test"
$password = ConvertTo-SecureString "test" -AsPlainText -Force
$cred = new-object -typename System.Management.Automation.PSCredential -argumentlist $username, $password
Start-Process "cmd.exe" -Credential $cred
This is all working fine for running an application from the user profile with no administrator rights that this script sits in, but when calling the cmd.exe it launches as expected with elevated rights but then immediately closes.
I have also tried calling it with the following:
Start-Process "cmd.exe" -Credential $cred -ArgumentList '/k'
This also is not working.
I tested the elevated permissions by passing in an argument as follows and this works fine.
Start-Process "cmd.exe" -Credential $cred -ArgumentList 'dir > dir.txt'
This will write out a dir.txt file to the C:\Windows\System32\WindowsPowerShell\v1.0 directory which is blocked on the user account but not for the administrator account test.
Any help on getting a persistent cmd window to show would be greatly appreciated.
Thanks

Note: SomeShinyObject came up with the fundamentals of the approach in his answer, but his parameter-passing technique is not robust (update: since corrected) - do not use script blocks in lieu of strings - see bottom.
-Verb RunAs is what makes Start-Process launch a process elevated.
However, -Verb RunAs cannot be combined with the -Credential parameter, so you cannot directly control under what user account the elevation happens - but that is generally not necessary:
If the current user is an administrator, elevation invariably happens in the context of that user, with the GUI prompt just asking for confirmation.
Otherwise, a GUI dialog is shown, asking for an administrator's username and password (with the username field blank).
Security caveats:
Storing a password as plain text is a security risk in general.
Additionally, if you let non-administrative users execute the code below with stored admin credentials, you're effectively giving them administrative rights.
If you still want to implement your script as specified, a workaround requires nesting 2 Start-Process calls:
The 1st one runs an (invariably) non-elevated command invisibly in the context of the specified user - assumed to be an administrative user - using -Credential.
Since the specified user is an administrator, it's not a concern here, but if -Credential targets a non-admin user, it is advisable to also specify a -WorkingDir argument that the specified user is known to have permissions to access - otherwise, the call may fail (the current location is retained, and the target user may not be allowed to access it).
The 2nd one, embedded in the 1st, then uses -Verb RunAs to run the target command elevated, which then happens in the context of the specified user.
Note: Even with a credentials object that includes the password, you will still get the yes/no UAC prompt to confirm the intent to elevate - unless UAC has been turned off (which is not advisable).
The working directory will invariably be $env:SYSTEMROOT\System32; -Verb RunAs ignores even a -WorkingDirectory value; if you want to change to a specific directory, embed a cd command in the command passed to cmd.exe; the bottom section of this related answer shows this technique with a powershell.exe / Set-Location call.
This command does exactly what you asked for - please note the security caveat:
# Construct the credentials object
$username = "jdoe"
# CAVEAT: Storing a password as plain text is a security risk in general.
# Additionally, if you let non-administrative users execute this
# code with a stored password, you're effectively giving them
# administrative rights.
$password = ConvertTo-SecureString "test" -AsPlainText -Force
$cred = New-Object PSCredential -Args $username, $password
# Start an elevated Command Prompt (cmd) as user $username.
Start-Process powershell.exe -Credential $cred -WindowStyle Hidden `
'-noprofile -command "Start-Process cmd.exe -Verb RunAs"'
Note that the embedded, 2nd command is passed as a single string to the (implied) -ArgumentList (a.k.a. -Args) parameter.
In this simple case, with only 1 level of embedded quoting - the " instances inside the '...' string - and no need for expansions (string interpolation), passing a single string is a viable option, but with more sophisticated commands quoting gets tricky.
-ArgumentList is defined as type [string[]], i.e., an array of string arguments. If you pass multiple, ,-separated arguments, it is PowerShell that synthesizes the command line for you:
Caveat: A long-standing bug unfortunately requires that argument with embedded spaces be enclosed in embedded double-quoting - see this answer for details.
The following command demonstrates this technique: It is a variant that passes a command for cmd.exe to execute through, and uses a variable reference in that command:
$msg = 'This is an elevated Command Prompt.'
Start-Process powershell.exe -Credential $cred -WindowStyle Hidden -Args `
'-noprofile', '-command', "Start-Process cmd.exe -Verb RunAs -Args /k, echo, '$msg'"
The cmd.exe command that is ultimately executed (with elevation) is:
cmd /k echo This is an elevated Command Prompt.
Optional Reading: Why using script blocks in lieu of strings is ill-advised
tl;dr
Do not get into the habit of using script blocks where strings are expected. While convenient, it is not robust, and remembering when and why it will fail is nontrivial.
At first glance, script blocks ({ ... }) seem like a convenient option:
Start-Process cmd -ArgumentList { /k echo hi! }
The above executes cmd /k echo hi! in a new console window, as expected.
The syntax is convenient, because the { ... } seemingly provide a context in which quoting is easy: you're free to use embedded " and ' instances to construct your command line.
However, what happens behind the scenes is that a script block is converted to a string, because that's the type of argument(s) -ArgumentList expects, and when a script block is converted to a string, its literal contents - everything between { and } - is used.
This means that no string interpolation takes place, so you cannot use variables or subexpressions.
Take this attempt to pass a command based on a variable:
Start-Process cmd -ArgumentList { /k echo Honey, I`'m $HOME! }
What this will execute is: cmd /k echo Honey, I'm $HOME! - $HOME was not expanded.
By contrast, passing either an interpolated string or the arguments individually works as intended:
# As a single string (argument list):
Start-Process cmd -ArgumentList "/k echo Honey, I'm $HOME!"
# As an array of arguments:
Start-Process cmd -ArgumentList /k, echo, "Honey, I'm $HOME!"
$HOME is expanded (interpolated) in both cases, and something like
cmd /k echo Honey, I'm C:\Users\jdoe is executed.

The best way is to double up your Start-Process first with a -Credential parameter with your admin credentials and then with a -Verb runas on your second Start-Process. After that it gets a little complicated with quoting for CMD.exe.
Overall, it should look something like this.
Start-Process PowerShell -ArgumentList {-noexit -noprofile -Command "Start-Process powershell -argumentlist {-command cmd.exe -args \"/K #yourcommands# \"}" -verb runas} -Credential $Cred
So scratch this. Read mklement0's answer as to why
There's always opportunity to learn more and I didn't know wrapping an ArgumentList in a ScriptBlock prevented variable expansion. So...don't do that.
The method stays the same, though. You'll still need two Start-Process calls, just now you have to get the quoting right.
#Both of these work
Start-Process powershell -Credential $cred -ArgumentList "-noprofile", "-command", "Start-Process cmd.exe -Verb RunAs -ArgumentList /k, echo, 'something'"
# $Something will expand into it's value rather than literally
Start-Process powershell -Credential $cred -ArgumentList "-noprofile", "-command", "Start-Process cmd.exe -Verb RunAs -ArgumentList /k, echo, '$something'"

Related

How can I properly escape a space in ArgumentList of Start-Process command nested within an ArgumentList of Start-Process command?

For a long time I've been using a powershell script containing the following line to automatically start various processes as a different user AND with elevated permissions:
start-process powershell -credential <username> -argumentlist '-command &{start-process <executable.exe> -verb runas -argumentlist <c:\path\to\file\that\executable-should-open.ext>}' -workingdirectory c:\windows\system32
Formatting it this way lets me simply create a convenient shortcut to the script. This works fine... as long as <c:\path\to\file\that\executable-should-open.ext> contains no spaces. However that file is now located at a filepath which contains spaces and that's something I cannot change.
There's countless threads out there dealing with how to properly escape the -ArgumentList parameter argument(s) of Start-Process, but none of the solutions seem to work for this case where the space is in the nested -ArgumentList. I've tried for days to find the magic sauce combination of single and double quotes, backticks, backslashes, $variables, $($variables), #("arguments","as","arrays"), not using &, etc., etc.
Can anyone help me achieve this? I'm certainly open to other solutions that don't use Start-Process, but ideally the working solution should work in a standalone script, and once run, should leave no additional console windows open.
With most attempts that don't outright throw errors, the behavior I'm seeing is that c:\path\to\file\with spaces\file.ext is interpreted by the nested Start-Process cmdlet as two separate arguments, i.e. c:\path\to\file\with and spaces\file.ext.
I use this syntax to open several different administrative apps, but as a concrete example, here is the one I've been testing and failing to make work.
Original, working script:
start-process powershell -credential domain\username -argumentlist '-command &{start-process mmc -verb runas -argumentlist c:\custom-aduc.msc}' -workingdirectory c:\windows\system32`
New, non-working script:
start-process powershell -credential domain\username -argumentlist '-command &{start-process mmc -verb runas -argumentlist c:\new path\custom-aduc.msc}' -workingdirectory c:\windows\system32
For reference, the reason I can't change the path is because the custom-aduc.msc is now being kept on OneDrive, which infuriatingly provides no way to change its local sync location from drive:\path\OneDrive - CompanyName. This is a heavily supported feature request for OneDrive, but has not been committed to.
Thanks for any insights.
P.S. I've considered alternate solutions such as:
Having the script first download/copy the files to a local path without spaces, however, this prevents me from using the executable to modify the file, or I'd have to monitor changes and re-upload them.
Mounting the OneDrive path as a separate drive letter. But that's much less of a standalone solution, and seems heavy handed.
TL;DR: To answer the titular question: It might be possible, but it's much easier to simply split the Start-Process commands into different scripts, to avoid nesting one inside the quotes of the other.
After lots more trial and error with escape syntax, I was able to find an acceptable solution. However I had to split it up into two separate script files, so as to avoid nesting the second Start-Process (and thus its -ArgumentList arguments) inside any other quotes.
script1.ps1
#runas /user:domain\username "powershell -file \`"c:\script2.ps1\`""
# Equivalent to the above, but provides a nicer credential prompt:
Start-Process -FilePath powershell -Credential domain\username -WorkingDirectory "c:\windows\system32" -ArgumentList "-File `"c:\script2.ps1`""
script2.ps1
Start-Process -FilePath mmc -Verb runas -ArgumentList "`"C:\path\with spaces\aduc.msc`""
The important part is that this way I can use the usual escaping methods for each -ArgumentList, without them interfering with each other. It may still be possible to use combinations of cmd interpreter escapes (\), and posh escapes (`) to do this all in one line, but I don't have the patience to figure that out. It also may be possible to hack this into a single script, but I can't be bothered.
At this point, I can simply create shortcuts which call script1.ps1 to achieve the desired result, just like I used to.
I like to use this for at least 3 different executables, and with 3 different usernames (my average joe account, and two different superuser accounts). To avoid needing two scripts for each executable+username combination, I generalized the scripts like so:
script1.ps1
$app = $args[0]
$user = $args[1]
$script2 = "C:\path\to\script2.ps1"
# Dont run as different user if this is my usual Windows login
# Otherwise I have to enter a password for no good reason
if($user -eq "domain\non-su-account") {
& powershell -file "$script2" $app
}
else {
#runas /user:$user "powershell -file \`"$script2\`" $app"
# Equivalent to the above, but provides a nicer credential prompt:
Start-Process -FilePath powershell -Credential $user -WorkingDirectory "c:\windows\system32" -ArgumentList "-File `"$script2`" $app"
}
script2.ps1
$app = $args[0]
switch($app) {
"aduc" {
Start-Process -FilePath mmc -Verb runas -ArgumentList "`"C:\path\with spaces\aduc.msc`""
break
}
"posh" {
Start-Process -FilePath powershell -Verb runas -ArgumentList "-nologo -noexit -command `"&{. \`"C:\path\with spaces\custom-powershell-profile.ps1\`"}`""
break
}
"posh-noprofile" {
Start-Process -FilePath powershell -Verb runas -ArgumentList "-nologo -noexit"
break
}
"mecm" {
& "C:\Program Files (x86)\Microsoft Endpoint Manager\AdminConsole\bin\Microsoft.ConfigurationManagement.exe"
break
}
}
So the shortcut targets look like:
C:\Windows\System32\WindowsPowerShell\v1.0\powershell.exe -file "C:\path\to\script1.ps1" aduc domain\username
Opening powershell and forcefully dot sourcing my custom profile script isn't really necessary, but it avoids the need to touch the powershell profiles of the superuser accounts, making this more portable.
Now that I've thoroughly demonstrated the weakness with which most markdown interpreters render nested/escaped powershell quotes, I bid you a good day. Hopefully this is useful to at least one other person ever again.

Trying to run a PowerShell script with admin rights by a user that doesnt have admin rights and the admin credentials are in the script [duplicate]

I am trying to launch an elevated CMD window from PowerShell but I am running into some issues. Below is the Code I have now. There is an admin account on the machine that has the username of "test" and a Password of "test"
$username = "test"
$password = ConvertTo-SecureString "test" -AsPlainText -Force
$cred = new-object -typename System.Management.Automation.PSCredential -argumentlist $username, $password
Start-Process "cmd.exe" -Credential $cred
This is all working fine for running an application from the user profile with no administrator rights that this script sits in, but when calling the cmd.exe it launches as expected with elevated rights but then immediately closes.
I have also tried calling it with the following:
Start-Process "cmd.exe" -Credential $cred -ArgumentList '/k'
This also is not working.
I tested the elevated permissions by passing in an argument as follows and this works fine.
Start-Process "cmd.exe" -Credential $cred -ArgumentList 'dir > dir.txt'
This will write out a dir.txt file to the C:\Windows\System32\WindowsPowerShell\v1.0 directory which is blocked on the user account but not for the administrator account test.
Any help on getting a persistent cmd window to show would be greatly appreciated.
Thanks
Note: SomeShinyObject came up with the fundamentals of the approach in his answer, but his parameter-passing technique is not robust (update: since corrected) - do not use script blocks in lieu of strings - see bottom.
-Verb RunAs is what makes Start-Process launch a process elevated.
However, -Verb RunAs cannot be combined with the -Credential parameter, so you cannot directly control under what user account the elevation happens - but that is generally not necessary:
If the current user is an administrator, elevation invariably happens in the context of that user, with the GUI prompt just asking for confirmation.
Otherwise, a GUI dialog is shown, asking for an administrator's username and password (with the username field blank).
Security caveats:
Storing a password as plain text is a security risk in general.
Additionally, if you let non-administrative users execute the code below with stored admin credentials, you're effectively giving them administrative rights.
If you still want to implement your script as specified, a workaround requires nesting 2 Start-Process calls:
The 1st one runs an (invariably) non-elevated command invisibly in the context of the specified user - assumed to be an administrative user - using -Credential.
Since the specified user is an administrator, it's not a concern here, but if -Credential targets a non-admin user, it is advisable to also specify a -WorkingDir argument that the specified user is known to have permissions to access - otherwise, the call may fail (the current location is retained, and the target user may not be allowed to access it).
The 2nd one, embedded in the 1st, then uses -Verb RunAs to run the target command elevated, which then happens in the context of the specified user.
Note: Even with a credentials object that includes the password, you will still get the yes/no UAC prompt to confirm the intent to elevate - unless UAC has been turned off (which is not advisable).
The working directory will invariably be $env:SYSTEMROOT\System32; -Verb RunAs ignores even a -WorkingDirectory value; if you want to change to a specific directory, embed a cd command in the command passed to cmd.exe; the bottom section of this related answer shows this technique with a powershell.exe / Set-Location call.
This command does exactly what you asked for - please note the security caveat:
# Construct the credentials object
$username = "jdoe"
# CAVEAT: Storing a password as plain text is a security risk in general.
# Additionally, if you let non-administrative users execute this
# code with a stored password, you're effectively giving them
# administrative rights.
$password = ConvertTo-SecureString "test" -AsPlainText -Force
$cred = New-Object PSCredential -Args $username, $password
# Start an elevated Command Prompt (cmd) as user $username.
Start-Process powershell.exe -Credential $cred -WindowStyle Hidden `
'-noprofile -command "Start-Process cmd.exe -Verb RunAs"'
Note that the embedded, 2nd command is passed as a single string to the (implied) -ArgumentList (a.k.a. -Args) parameter.
In this simple case, with only 1 level of embedded quoting - the " instances inside the '...' string - and no need for expansions (string interpolation), passing a single string is a viable option, but with more sophisticated commands quoting gets tricky.
-ArgumentList is defined as type [string[]], i.e., an array of string arguments. If you pass multiple, ,-separated arguments, it is PowerShell that synthesizes the command line for you:
Caveat: A long-standing bug unfortunately requires that argument with embedded spaces be enclosed in embedded double-quoting - see this answer for details.
The following command demonstrates this technique: It is a variant that passes a command for cmd.exe to execute through, and uses a variable reference in that command:
$msg = 'This is an elevated Command Prompt.'
Start-Process powershell.exe -Credential $cred -WindowStyle Hidden -Args `
'-noprofile', '-command', "Start-Process cmd.exe -Verb RunAs -Args /k, echo, '$msg'"
The cmd.exe command that is ultimately executed (with elevation) is:
cmd /k echo This is an elevated Command Prompt.
Optional Reading: Why using script blocks in lieu of strings is ill-advised
tl;dr
Do not get into the habit of using script blocks where strings are expected. While convenient, it is not robust, and remembering when and why it will fail is nontrivial.
At first glance, script blocks ({ ... }) seem like a convenient option:
Start-Process cmd -ArgumentList { /k echo hi! }
The above executes cmd /k echo hi! in a new console window, as expected.
The syntax is convenient, because the { ... } seemingly provide a context in which quoting is easy: you're free to use embedded " and ' instances to construct your command line.
However, what happens behind the scenes is that a script block is converted to a string, because that's the type of argument(s) -ArgumentList expects, and when a script block is converted to a string, its literal contents - everything between { and } - is used.
This means that no string interpolation takes place, so you cannot use variables or subexpressions.
Take this attempt to pass a command based on a variable:
Start-Process cmd -ArgumentList { /k echo Honey, I`'m $HOME! }
What this will execute is: cmd /k echo Honey, I'm $HOME! - $HOME was not expanded.
By contrast, passing either an interpolated string or the arguments individually works as intended:
# As a single string (argument list):
Start-Process cmd -ArgumentList "/k echo Honey, I'm $HOME!"
# As an array of arguments:
Start-Process cmd -ArgumentList /k, echo, "Honey, I'm $HOME!"
$HOME is expanded (interpolated) in both cases, and something like
cmd /k echo Honey, I'm C:\Users\jdoe is executed.
The best way is to double up your Start-Process first with a -Credential parameter with your admin credentials and then with a -Verb runas on your second Start-Process. After that it gets a little complicated with quoting for CMD.exe.
Overall, it should look something like this.
Start-Process PowerShell -ArgumentList {-noexit -noprofile -Command "Start-Process powershell -argumentlist {-command cmd.exe -args \"/K #yourcommands# \"}" -verb runas} -Credential $Cred
So scratch this. Read mklement0's answer as to why
There's always opportunity to learn more and I didn't know wrapping an ArgumentList in a ScriptBlock prevented variable expansion. So...don't do that.
The method stays the same, though. You'll still need two Start-Process calls, just now you have to get the quoting right.
#Both of these work
Start-Process powershell -Credential $cred -ArgumentList "-noprofile", "-command", "Start-Process cmd.exe -Verb RunAs -ArgumentList /k, echo, 'something'"
# $Something will expand into it's value rather than literally
Start-Process powershell -Credential $cred -ArgumentList "-noprofile", "-command", "Start-Process cmd.exe -Verb RunAs -ArgumentList /k, echo, '$something'"

Start-Process -WorkingDirectory as administrator does not set location

When I enter the command
Start-Process powershell -WorkingDirectory "D:\folder"
it opens new PowerShell window with D:\folder location set.
But when I enter the command
Start-Process powershell -WorkingDirectory "D:\folder" -Verb RunAs
it opens new PowerShell window with admin rights but with C:\Windows\system32 location set.
How can I open new PowerShell window with admin rights and my own location determined?
I also had the same problem and solved it with this command:
Start-Process powershell.exe -verb runAs -ArgumentList '-NoExit', '-Command', 'cd D:\folder'
Once you run the above command, Windows will launch with admin authority and the specified directory.
Here's another example which can be used for opening CMD from PowerShell as an administrator into the current folder:
Start-Process cmd -ArgumentList ("/k cd {0}" -f (Get-Location).path) -Verb RunAs
if used within a script you can use
Start-Process cmd -ArgumentList ("/k cd {0}" -f $PSScriptRoot) -Verb RunAs
If you want to open a new elevated PowerShell session from the current one which is not elevated you can use:
Start-Process powershell.exe -ArgumentList ("-NoExit",("cd {0}" -f (Get-Location).path)) -Verb RunAs
or
Start-Process powershell.exe -ArgumentList ("-NoExit",("cd {0}" -f $PSScriptRoot)) -Verb RunAs
when used inside scripts
When using Start-Process with -Verb RunAs, a -WorkingDirectory argument is honored if the target executable is a .NET executable; examples:
pwsh.exe (the PowerShell (Core) CLI) does honor it.
cmd.exe and, curiously, powershell.exe (the Windows PowerShell CLI) do not, and invariably use C:\Windows\System32.
The problem exists at the level of the .NET API that PowerShell uses behind the scenes (see System.Diagnostics.ProcessStartInfo), as of this writing (.NET 6.0.0-preview.4.21253.7).
Unless you know that you're invoking a .NET executable, a workaround that changes to the desired working folder in the new process is therefore required; to offer a more robust alternative to ふゆな's helpful answer:
$dir = $PWD.ProviderPath # use the current dir.
Start-Process -Verb RunAs powershell.exe #"
-noexit -c Set-Location -LiteralPath "$dir"
"#
The embedded "..." quoting around $dir ensures that paths with spaces are also handled correctly. (To use the current directory without an intermediate variable, replace "dir" with "$($PWD.ProviderPath)".
Using a here-string (#"<newline>...<newline>"#) isn't strictly necessary, but simplifies the embedded quoting; with a regular expandable string ("..."), the embedded " must be escaped as `" (or "").
Using $PWD's .ProviderPath property ensures that a file-system-native path is used (based on drive letters also seen in cmd.exe, for instance), given that the calling session's current location may be based on a PowerShell-only drive (see New-PSDrive) that the elevated process may not have defined (at all or not based on the same root location).
Caveat: If the native path is on a mapped network drive, this won't work, because elevated processes do not see the same drive mappings; in that event, pass the underlying UNC path.
Workaround for launching a GUI application elevated from a given working directory:
Since changing to the working directory must happen in the new, elevated process, a helper shell process is needed to perform this operation, which is best done via cmd.exe (for better performance):
$exeToLaunch = 'Notepad.exe' # may include arguments
$dir = $PWD.ProviderPath # use the current dir.
Start-Process -Verb RunAs -WindowStyle Hidden cmd.exe #"
/c cd "$dir" & $exeToLaunch
"#
Once you run Powershell as administrator;
user the push-location command like so:
Push-Location -Path C:\
or put it into your script and run the script from the elevated Powershell prompt.
I just ran your code example and it opened correctly for me at the WorkingDirectory location. Ensure the directory exists before you run the command. I tested against a drive on C and secondary drive as well and both worked.

Error when trying to run .bat file using runas Administrator using PowerShell

I can right click on the DEC16.bat file and it will run. I am having trouble including it in a script to run from a flash drive.
The PowerShell script essentially copies over a bunch of install files onto a client's computer.
Windows PowerShell
Copyright (C) 2013 Microsoft Corporation. All rights reserved.
PS H:\> $script = "\\xxxhsfmsl03\adap\Database\Install\AugKA\DEC16.bat"
PS H:\>
PS H:\> Start-Process powershell -Credential “xxx\xxxvis_desktop” -ArgumentList '-noprofile -command &{Start-Process $script -verb runas}'
Start-Process : This command cannot be run due to the error: The directory name is invalid.
At line:1 char:1
+ Start-Process powershell -Credential “xxx\xxxvis_desktop” -ArgumentList '-noprof ...
+ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ CategoryInfo : InvalidOperation: (:) [Start-Process], InvalidOperationException
+ FullyQualifiedErrorId : InvalidOperationException,Microsoft.PowerShell.Commands.StartProcessCommand
PS H:\> $script
\\xxxhsfmsl03\adap\Database\Install\AugKA\DEC16.bat
PS H:\>
(I have inserted "xxx"'s to protect the innocent)
Try the following:
Start-Process powershell `
-WorkingDirectory (Split-Path $script) `
-Credential xxx\xxxvis_desktop `
-ArgumentList '-noprofile', '-command', "
& { start-process powershell -ArgumentList '-File', '$script' -Verb RunAs }
"
Your primary problem was most likely that the target user - xxx\xxxvis_desktop - lacked permission to access what happened to be the current directory at the time of invocation.
Setting the working directory explicitly to a directory the target user is allowed to access should fix that problem - -WorkingDirectory (Split-Path $script) sets the working dir. to the dir. in which the target script is located.
Your secondary problem - as pointed out in a comment on the question by Matt - is that the command string you passed to Start-Process was enclosed in '...' (single quotes), causing the embedded $script variable reference not to be expanded (interpolated).
Using "..." (double quotes) fixes that problem; note, however, that the command line to pass to the powershell executable is split into individual arguments passed via -ArgumentList - the (literal, single-quoted) options, followed by the (interpolated, double-quoted) command string, which is the preferable way to pass arguments, because it is more robust.
Note, how the $string reference inside the command string is enclosed in embedded '...' so as to ensure that when the invoked powershell instance parses the command string, the value of $string is recognized as a single argument (although this happens not to be necessary for the value at hand, \\xxxhsfmsl03\adap\Database\Install\AugKA\DEC16.bat).
If there's a chance that the value of $script has embedded ' instances, you must use the following (double the ' instances to escape them):
$($script -replace "'", "''")
The final problem is that you cannot use Start-Process directly on a script - as in the outer call, you need to call powershell and pass it the script filename as an argument.
Additional notes:
The & { ... } wrapper around the start-process call in the command string shouldn't be necessary.
Generally, you could use a single Start-Process call with -Verb RunAs to elevate the run of $script, but, unfortunately, -Verb RunAs and -Credential cannot be combined, so that means:
If the current user is an administrative account, the elevated session will invariably run as that user - you'll just get a yes/no prompt to confirm elevation.
Otherwise, the credentials will be prompted for, but you cannot pre-populate the username in that dialog.
Start-Process -Verb RunAs powershell -ArgumentList '-noprofile', '-File', $script

Start-Process with auto elevated permissions and passing command inline

I need to start a windows service on the local computer through PS by directly running the PS script w.o the need to manually elevate the permissions. This code works for me:
Start-Process powershell -Verb runas -ArgumentList "-file MyFileName.ps1"
Where MyFileName.ps1 contains:
Start-Service MyServiceName
But I want to keep it simple and instead of storing the command into a separate file, I want to run a single script. The following does not work for me:
Start-Process powershell -Verb runas -ArgumentList "-command '& {Start-Service MyServiceName}'"
What am I missing?
Start-Process invokes a new process. The invocation doesn't recognize single quotes as quoting characters, so instead of passing a parameter -command with a command string '&{Start-Service MyServiceName}' you're passing 4 tokens: -command, '&, {Start-Service, and MyServiceName}.
Change this:
"-command '& {Start-Service MyServiceName}'"
into this:
"-command `"& {Start-Service MyServiceName}`""