I am trying to install a service 'ServiceName' from the command prompt, with parameter values which I am taking as user input forms through powershell.
$server = $return[0]
Invoke-Expression -Command "cmd.exe /c ServiceName --install --server=$server"
Basically the ServiceName service takes parameter values from server variable while installing. I am not exactly sure if this is the correct way of using powershell variable values in cmd.exe. Can the cmd.exe take in the server variable value in the manner shown above?
You can add new services in Powershell, and you dont have to use cmd for that:
$serviceName= Read-Host("Enter service name")
$mycreds = Get-Credential
$binaryPath = Read-Host("Enter service executable path")
New-Service -name $serviceName -binaryPathName $binaryPath -displayName $serviceName -startupType Automatic -credential $mycreds
Also you can use
Get-Help New-Service
If you want additional parameters passed to the command. Or if you want, you can parse if from a single input, but its more messy.
Related
$secpasswd = ConvertTo-SecureString "Password" -AsPlainText -Force
$mycreds = New-Object System.Management.Automation.PSCredential("administrator", $secpasswd)
$Path = "$env:userprofile\AppData\Local"
cd "$Path\telegraf"
$installtelegraf = .\telegraf.exe --service install --config "$Path\telegraf\telegraf.conf"
$start_telegraf = telegraf.exe --service start
$net_telegraf = net start telegraf
Start-Process Powershell.exe -Credential $mycreds -ArgumentList $installtelegraf $start_telegraf $net_telegraf
But don't know I am getting errors. I'll use this script for automation process to install it on our clients through Group Policy.
Any kind of help will be appreciated.
Thanks.
Your intent is to define the command lines to invoke later with Start-Process as strings, and for that you must use quoting; e.g.:
# Without enclosure in '...' you would *instantly* execute the command.
$start_telegraf = 'telegraf.exe --service start'
To put it all together:
$installtelegraf = "telegraf.exe --service install --config `"$Path\telegraf\telegraf.conf`""
$start_telegraf = 'telegraf.exe --service start'
$net_telegraf = 'net start telegraf'
Start-Process Powershell.exe -Credential $mycreds -ArgumentList #"
$installtelegraf
$start_telegraf
$net_telegraf
"#
Note:
The $installtelegraf = ... assignment uses an expandable (double-quoted) string ("..."), so as to ensure that expansion (string interpolation) takes place, i.e. so that $Path is expanded (replaced with its value); the embedded " chars. must therefore be escaped as `".
Since the other assignments do not require expansion, verbatim (single-quoted) strings ('...') are used.
Note the use of an expandable here-string in the Start-Process call, to make it easy to pass the three variables as separate statements; alternatively, you could have used a single-line string with ; as the statement separator.
Note that I've removed .\ from the first telegraf.exe call, as it doesn't appear in the second.
Generally, note that the target user must have permission to access the caller's working directory. If not, a different one must be specified via -WorkingDirectory.
So I have automation that logs into a Windows Server 2019 machine as one user, but then needs to run a command (Invoke-AdminCommand is application specific, not a built-in Windows cmdlet) as an admin user (and I do not want to add the logged in user as an Admin). I've followed answers from here (if you think this is a duplicate question) and none have worked. In the script I do a "whoami" to be sure the session is the correct user, and it is. But the command returns an application specific error stating the user does not have the correct permissions. If I RDP into the same machine as the admin user and run the same command through a Powershell CLI - it works fine.
$username = "domain\adminUser"
$password = "**********" | ConvertTo-SecureString -AsPlainText -Force
$cred = New-Object System.Management.Automation.PSCredential -ArgumentList $username,$password
$s = New-PSSession -credential $cred
$sc = {
whoami
Invoke-AdminCommand -Register -Verbose
}
Invoke-Command -Session $s -Scriptblock $sc
Remove-PSSession $s
You may be hitting the double-hop problem. You are remoting to another server to run another command which itself requires authentication. If you can't lean on CredSSP (security risk) or proper account delegation (potentially high overhead in effort to maintain delegations at volume but this is the correct way to go about it).
Note: Basic auth will also work around this issue but I highly highly highly do not recommend using basic auth without at least setting up WinRM over SSL and removing non-HTTPS WinRM listeners.
Whether you are using Kerberos (without proper delegation or CredSSP) or NTLM (at all as NTLM cannot forward tokens) as the authentication scheme you can work around this by passing the credential information into Invoke-Command and building the credential in that script block, and using Start-Process to start it as a different user. Note that if you needed to elevate for UAC, the code would be different and this code will only work when you don't need UAC elevation:
# We will create the SecureString inside the Invoke-Command block
$password = "********"
# Use of a Dictionary instead of positional arguments and `param` in the block
# is a little trick you can use here.
Invoke-Command -Session $s -ArgumentList #{ Username = $username; Password = $password } {
$cred =
[PSCredential]::new($args.Username, ( $args.Password | ConvertTo-SecureString -AsPlainText -Force ))
# Placeholder for next part
}
So this is the boilerplate for what you want. You send the credentials to the remote server and build it there. How you execute this at # Placeholder for next part will depend on what exactly you are running:
External Command (executable)
Use Start-Process to run the program as the other user
Start-Process -Wait -Credential $cred program.exe -ArgumentList "arguments to the program here"
Any cmdlet which accepts a -Credential parameter or any command which accepts username and password arguments
Pass the credential argument directly to the cmdlet/function, or pass $args.Username and $args.Password to an external command which has username/password parameters directly. The below however exemplifies using this with a cmdlet and the -Credential parameter.
# Note that some cmdlets don't take a credential for whatever reason
# and may have -Username and -Password arguments instead.
Invoke-AdminCommand -Credential $cred -Register -Verbose
Any Function or Cmdlet which does not accept a -Credential parameter or username/password arguments
This is similar to the first example, but this example specifically targets running a bit of PowerShell code as another user for the code you want.
# This can be invoked without splatting but am using splatting for readability
$spArgs = #{
Credential = $cred
FilePath = 'powershell.exe' # You can use `pwsh.exe` for PS Core if necessary
ArgumentList = "-Command ""exampleProgram.exe -username $($args.Username) -password $($args.Password)"""
Wait = $true
NoNewWindow = $true
}
Start-Process powershell.exe
I'm programatically launching a Google Cloud Compute Instance running Windows Server 2016 with a start up script.
The executable in the start up script requires to be launched as a specific user, so I'm trying to launch it with psexec to simulate said user:
C:/psexec.exe \\\\WIN-SERVER-2016 -u WIN-SERVER-2016\\customuser -p custompassword -accepteula -w "c:/app" cmd /c node index.js
c:/app/index.js contains a simple hello world, which should write to a file.
If I log in as any user and launch this exact command from cmd, the file is written. Launching from the startup script (supplied as windows-startup-script-cmd in the Google Cloud Compute Engine Instance) results in no file written.
What could be the solution? Is there a more efficient way to execute a start-up script as a specific user?
Looking at the concern , I would not recommend you to use PSEXEC .
NOrmally, we use PSExec in order to invoke a GUI in the remote system which PS doesn't support by native.
In your case, I would suggest you to run using the Invoke-Command
Something like this:
$username = 'WIN-SERVER-2016\customuser'
$password = "custompassword"
$secstr = New-Object -TypeName System.Security.SecureString
$password.ToCharArray() | ForEach-Object {$secstr.AppendChar($_)}
$cred = new-object -typename System.Management.Automation.PSCredential -argumentlist $username, $secstr
$Script_block = {cmd /c node index.js}
Invoke-Command -ComputerName WIN-SERVER-2016 -Credential $cred -ScriptBlock $Script_block
This should also take it from the Metadata key if you are using windows-startup-script-cmd
Note: I have not considered the accepteula -w "c:/app" part. Please incorporate the placeholders accordingly.
Hope it helps...!!!
Quick question. I am trying to write the following PowerShell script, but I would like it to fit on a single line:
$app = New-Object -comobject Excel.Application
$wb1 = $app.Workbooks.Open("C:\xampp\upload_files\Launchpad.xlsm")
$app.Run("Refresh")
$wb1.Close($false)
$app.Quit()
The pseudo-code would look something like this:
$app = New-Object -comobject Excel.Application AND $wb1 = $app.Workbooks.Open AND "C:\xampp\upload_files\Launchpad.xlsm") AND $app.Run("Refresh") AND $wb1.Close($false) AND $app.Quit()
The reason I want to fit on a line is because I would like to insert the arguments directly in the 'arguments' box of Windows Task Scheduler. The reason for this is that for some reason scripts have been disabled (e.g. I cannot call a .ps1 file...)
I know this will still work, as I already have a "one liner" PS script running. What would the syntax look like??
Kind regards,
G.
Powershell statements can be separated with semicolons:
$app = New-Object -COM 'Excel.Application'; $wb1 = $app.Workbooks.Open("..."); ...
The PowerShell executable takes a -Command parameter that allows you to specify a command string for execution in PowerShell:
powershell.exe -Command "stmnt1; stmnt2; ..."
To run this via Task Scheduler you'd put powershell.exe into the "program" field and -Command "stmnt1; stmnt2; ..." into the "arguments" field of the task.
However, as #alroc said: you should verify why script execution has been restricted. If it's just the default setting you can simply change it by running Set-ExecutionPolicy RemoteSigned or override it by adding -ExecutionPolicy ByPass to a PowerShell command line. However, if the setting is enforced by policy changing/bypassing the setting will fail, and you could get into quite some trouble for violating company policies.
Here is a solution that you might use if the script is not that easy to convert, but you are on Windows running at least PowerShell V5.
It converts the code into Base64 and uses PowerShell.exe with the parameter -encodedCommand to pass the encodedCommand as string.
$command = Get-Content .\YourPowerShellFileContainingTheCode.ps1 -raw
# Get-Content may require "-encoding utf8" or other encodings depending on your file
$encodedCommand = [Convert]::ToBase64String([Text.Encoding]::Unicode.GetBytes($command))
Write-Output "Text for application:"
Write-Output "PowerShell.exe" ""
Write-Output "Text for argurments:"
Write-Output "-encodedCommand $encodedCommand"
It would look like this, but with a much larger command:
Text for application:
PowerShell.exe
Text for argurments:
-encodedCommand SABvACAASABvACAASABvACwAIABzAHQAYQBjAGsAbwB2AGUAcgBmAGwAbwB3AA==
From my script I want to run some command in remote Windows box. So I googled a little and seems the most popular and somehow standard way to do that is to use PowerShell's Invoke-Command cmdlet which seems to use the same protocol as winrm and winrs. So, bellow are commands I've tried to call from my script (actually I've tried lots of other their modifications as well, but IMO these are enough to illustrate the problem):
PowerShell -Command "$encpass=ConvertTo-SecureString -AsPlainText mypass -Force;$cred = New-Object System.Management.Automation.PSCredential -ArgumentList myuser,$encpass; Invoke-Command -ComputerName REMOTE_COMPUTER_NAME -Credential $cred -ScriptBlock {<fullcommand>};"
PowerShell -Command "$encpass=ConvertTo-SecureString -AsPlainText mypass -Force;$cred = New-Object System.Management.Automation.PSCredential -ArgumentList myuser,$encpass; Invoke-Command -ComputerName REMOTE_COMPUTER_NAME -Credential $cred -ScriptBlock {Start-Process -FilePath <fullexepath> -ArgumentList <arguments> -Wait -NoNewWindow};"
PowerShell -Command "$encpass=ConvertTo-SecureString -AsPlainText mypass -Force;$cred = New-Object System.Management.Automation.PSCredential -ArgumentList myuser,$encpass;$session=new-PSSession -ComputerName "REMOTE_COMPUTER_NAME" -Credential $cred; Invoke-Command -Session $session -ScriptBlock {<fullcommand>};"
NOTE: The script is written in perl, but IMO here the language of the script doesn't matter, so you can suppose that I call the command from batch script, just note, that as commands should run from a script they should not require any interactive actions.
So, I have several problems with these commands, and need help to figure them out. Here they are:
Can't run processes of type configure and run daemon. Namely if I want to run configure_server.pl on remote box (<fullcommand> = "configure_server.pl <arguments>"), which should do some stuff, then run server.exe, it doesn't work, because as soon as configure_server.pl is done, full remote job is being killed including the server.exe which supposed to run as a daemon. (applies to points 1,2,3)
Get wrapped (length of each line is less or equal than 80 chars) standard output and standard error. (applies to point 1,3)
Don't get standard output and standard error. (applies to point 2)
Whew this is a tough one, your kind of all over the place so if I miss what your trying to do completely let me know.
1 . Stop trying to go the remote route. I know it seems like a great idea, but it's not. The only way you can get the process to persist is if you keep the powershell window up on the host computer. As you've probably noticed, you can create processes fine, but they're children of your powershell.exe, and are hosted by the wsmprovhost.exe process on the client computer. Once the parent is gone, all the children are killed
To fix this I suggest using a command line function : Schtasks.exe
schtasks.exe /create /sc ONCE /tn $taskName /tr $command /s $serverName /u $userName /p $pass /ru $userName /rp $pass /st $startTime
This command is going to create a scheduled task to run once and then remove itself after. It even takes computer name, so no remote-access required. You can also do a schtasks.exe /query and check the "Status" for running before you do a schtasks.exe /delete too.
2 . Use the ` (backtick) to specify carry execution to the next line in powershell
3 . I get standard output and error with this function, sometimes not output when executed in a big script, but can always use $? to capture error.
Note: You cannot pass in PSCredentials to this command. I suggest making a GUI that just prompts for userName and and password, without converting to secure string. I try to stay away from remoting in my scripts, since it always just makes everything so slow. Sometimes you do not have a choice, but in this case I believe you do.