Have very useful script named sudo.ps1:
$w=""; foreach($a in $args[1..($args.length-1)] ){ $w += " " + $a }; $w
Start-Process $args[0] -ArgumentList $w -Verb RunAs -Wait
but it can't handle complex command
./sudo.ps1 schtasks /create /F /TN "$vpn_name Connection Update" /TR "Powershell.exe -noexit -command D:\vpn-route.ps1" /SC ONEVENT /EC Application /MO "*[System[(Level=4 or Level=0) and (EventID=20225)]] and *[EventData[Data='$vpn_name']]" /RL HIGHEST
Problem is in obfuscated quotes. In sudo.ps1 quotes are opened:
/create /F /TN VPN-Kosmos6 Connection Update /TR Powershell.exe -noexit -command D:\vpn-route.ps1 /SC ONEVENT /EC Application /MO *[System[(Level=4 or Level=0) and (EventID=20225)]] and *[EventData[Data='VPN-Kosmos6']] /RL HIGHEST
Command executed with no error, but does no work. How can it be fixed?
If arg contains space, add quotes via """ (thanks to PetSerAl). Now sudo.ps1 works fine:
$w=""; foreach($a in $args[1..($args.length-1)] ){ $w+=" "; if($a -match " "){$w+="""$a"""}else{$w+=$a} }; $w
Start-Process $args[0] -ArgumentList $w -Verb RunAs -Wait
Consider another solutions suggested by Keith Hill and Bill_Stewart, if looking for better and more complex decision.
Related
I want to call another powershell script with external argument. I try this but return error. anyone can help please
$direct = "D:\Learn"
Start-Process powershell.exe -WindowStyle Minimized ".\Testing.exe" -Path $direct
Testing.exe
Param(
[parameter(mandatory=$true)][string]$Loc
)
Get-Content $Loc\API.txt
Pause
The Start-Process cmdlet has a -AgumentList parameter:
$direct = "D:\Learn"
Start-Process powershell.exe -WindowStyle Minimized ".\Testing.exe" -ArgumentList "-Path $direct"
If you want to just run a File with some arguments
$filepath = ".\Testing.exe"
$direct = "D:\Learn"
Start-Process -FilePath $filepath -ArgumentList $direct -Wait -NoNewWindow
I think they all were arguments of powershell.exe.
The whole argument can be wrapped in one double quote in argumentlist.
Start-Process "powershell.exe" -ArgumentList "-windowstyle minimized '.\testing.exe' -path $direct"
Or even it can be done without start-process:
& "powershell.exe -windowstyle minimized '.\testing.exe' -path $direct"
I've read that you can pass arguments to a .msi file, but I have no idea how to do it correctly. I've tried the following, where $ArgumentList is an array.
$ArgumentList = #("/i .\NSClient v67.msi", "/norestart", "/quiet", "/l*v '$directory'", "token=$token", "host=$_host", "mode=$mode")
Start-Process "msiexec" -ArgumentList $ArgumentList -Wait -NoNewWindow
This is part of my script, where I'm trying to install NetSkope on my machine by executing a command.
In theory, the command should look like msiexec /i "NSClient v67.msi" token=loremipsum host=bryan.goskope.com mode=peruserconfig /norestart /quiet /l*v "C:\Temp\NetskopeInstallation.log.
#Find file path
$rawPath = Invoke-Expression -Command 'C:\Windows\System32\WHERE /r C:\Users\ /f NSClient*.msi'
#Extract the directory
$filePath = Invoke-Expression -Command "cmd.exe --% /c FOR /f ""tokens=1"" %A IN ($rawPath) DO (ECHO
'%~dpA')"
#Cast $filePath to work with string methods
$filePath = Out-String -InputObject $filePath
$filePath = $filePath.split("'")[1]
Invoke-Expression -Command "cmd.exe --% /c cd $filePath"
$ArgumentList = #("/i .\NSClient v67.msi", "/norestart", "/quiet", "/l*v '$directory'",
"token=$token", "host=$_host", "mode=$mode")
Start-Process "msiexec" -ArgumentList $ArgumentList -Wait -NoNewWindow
I would also recommend using the Powershell MSI Module
Concerning Start-Process:
-Argumentlist expects string as a type. I don't think you can just pass an array.
You also need to surround the parameters that require a space with escaped double quotes. The escape character is powershell is the grave-accent(`).
Another problem is that the variable $directory will never be expanded, because it is surrounded with single quotes. You need to remove those.
The following should work for your example, but I personally would just remove the space in the file name, since you don't need to do weird stuff with escaping.
Without escaping:
$ArgumentList = "/i .\NSClientv67.msi /norestart /quiet /l*v $directory token=$token host=$_host mode=$mode"
With escaping:
$ArgumentList = "/i `".\NSClient v67.msi`" /norestart /quiet /l*v $directory token=$token host=$_host mode=$mode"
Here's a slightly different syntax:
$MSIArguments = #(
"/x"
"`"C:\path with spaces\test.msi`""
"/qb"
"/norestart"
"/l*v"
"`"C:\path with spaces\test.log`""
)
Start-Process "msiexec.exe" -ArgumentList $MSIArguments -Wait -NoNewWindow
I have been unable to understand why the following command don't trigger the silent installation of Power-Bi -
Start-Process msiexec -wait -ArgumentList '/i $ENV:Temp\PBIDesktop_x64.msi /qn /norestart ACCEPT_EULA=1'
where as the following works -
Start-Process msiexec -wait -ArgumentList '/i C:\Users\ADMINI~1\AppData\Local\Temp\PBIDesktop_x64.msi /qn /norestart ACCEPT_EULA=1
'
I am using an elevated ISE but the first command generates no errors and does nothing. I think that the $ENV:TEMP is not expanding. Please help.
regards,
Prateek
Powershell won't extend anything in a string if you're using single-quoted-ticks instead of double quotes. So change your code to:
Start-Process msiexec -wait -ArgumentList "/i $ENV:Temp\PBIDesktop_x64.msi /qn /norestart ACCEPT_EULA=1"
This link describes the quotation rules.
In short:
> $i = 1
> "Double quotes: $i + $i"
Double quotes: 1 + 1
> 'Single quotes: $i + $i'
Single quotes: $i + $i
Hope that helps
I am writing a powershell function that runs on a Server to schedule a powershell script to run on each Windows 7 client machine by using schtasks.exe.
If I do not provide a user name and password, the script only runs if the client is logged in as administrator.
If I do provide a user name and password, I get two errors:
(1) System cannot find the file specified
(2) A specified logon session does not exist. It may already have been terminated.
How do I get the scheduled job to run properly even if the admin account is not logged it?
Thanks!
function scheduleRemoteScript($computerList) {
foreach ($computer in $computerList) {
$ts = New-TimeSpan -Minutes 1
$currentDateTime = (get-date) + $ts
$hour = $currentDateTime.Hour.ToString()
if ($hour.Length -eq 1) {
$hour = '0' + $hour
}
$minute = $currentDateTime.Minute.ToString()
if ($minute.Length -eq 1) {
$minute = '0' + $minute
}
$timeString = $hour + ":" + $minute
schtasks.exe /Delete /TN LocalScript /S $computer /F #delete the task in case it aleady exists.
#this runs when logged in with admin account, but not user account.
#schtasks.exe /create /TN LocalScript /S $computer /ST $timeString /SC ONCE /TR "powershell.exe -file C:\localScript.ps1"
#this gives two errors: (1) system cannot find the file specified (2) a specified logon session does not exist. It may already have been terminated.
schtasks.exe /create /TN LocalScript /S $computer /ST $timeString /SC ONCE /TR "powershell.exe -file C:\localScript.ps1" /RU 'admin-account' /RP 'somePassword'
}
}
ScriptToInvoke.ps1:
[CmdletBinding()]
param (
[Parameter(Mandatory=$True)]
[string[]]$StringArray,
[ValidateSet('Mode1', 'Mode2', 'Mode3')]
[string]$Mode = 'Mode1'
)
$count = $StringArray.Count
Write-Verbose ("String array count ($count): $StringArray")
ScriptCallingStartProcess.ps1:
$stringArray = #('String1','String2','String3')
Start-Process powershell -Verb RunAs
-ArgumentList "-NoExit -File ScriptToInvoke.ps1 -StringArray ""$stringArray"" -Mode Mode3 -Verbose"
In this case the $stringArray is treated as an array containing one element:
screen capture of script run output
I have tried multiple variations passing the $stringArray argument:
-StringArray $stringArray
-StringArray #($stringArray)
-StringArray #(,#($stringArray))
each with the same error:
A positional parameter cannot be found that accepts argument 'String2'
As I understand it the double quotes around the ArgumentList value result in any variable being parsed. Is it possible to prevent this from happening? Or is there an alternative approach?
My use case involves attempting to re-run the Powershell script with elevated permissions to uninstall a Windows update, which is why I use Start-Process with -Verb RunAs.
Here's one way. ScriptCallingStartProcess.ps1:
$stringArray = #('String1','String2','String3')
$OFS=","
Start-Process powershell.exe -Verb Runas "-NoExit -File \ScriptToInvoke.ps1 $stringArray -Mode Mode3 -Verbose"
ScriptToInvoke.ps1:
[CmdletBinding()]
param (
[Parameter(Mandatory=$True)]
[String] $InputData,
[ValidateSet('Mode1', 'Mode2', 'Mode3')]
[string]$Mode = 'Mode1'
)
$StringArray = $InputData -split ','
$count = $StringArray.Count
Write-Verbose ("String array count ($count): $StringArray")
(that is, pass a comma-delimited string as first parameter, then split inside second script)
I escaped the double quotes, and it seems to work ok:
Start-Process powershell -Verb RunAs -ArgumentList "-NoExit -File test.ps1 -StringArray `"$stringArray`" -Mode Mode3 -Verbose"