I am using psexec to execute a .bat on a system. This will fingerprint the system and return the info back to me. The command I use is:
psexec \\server -u username -p password -s -i -c .\fingerprint.bat
This works with most of the servers, but some of them won't work with the -i switch. Is there a way to say, if this fails, try to do it again without the -i? I am using powershell to execute the script.
$servers = get-content .\input.txt
foreach($server in $servers) {
psexec \\$server -u username -p password -s -i -c .\fingerprint.bat
}
Check the $LastExitCode automatic variable. This gets set when PowerShell invokes an EXE. Whatever exit code the EXE returns gets put in $LastExitCode. I'm pretty sure psexec returns 0 for success and anything else means failure e.g.:
foreach($server in $servers) {
psexec \\$server -u username -p password -s -i -c .\fingerprint.bat
if ($LastExitCode) {
psexec \\$server -u username -p password -s -c .\fingerprint.bat
}
}
This is using a PowerShell trick where if ($LastExitCode) will if evaluate to true if $LastExitCode is anything but 0.
Related
I have the following code:
foreach ($program in $programlist){
"$line installed $program" | Out-File "$logpath\log.txt" -Append
psexec \\"$hostikname" -u bla\bla -p $plainpwd cmd /c "pushd $BucketPath & copy $program c:\programdata\"
psexec \\"$hostikname" -i -u bla\bla -p $plainpwd -h cmd /c "c:\programdata\$program"
psexec \\"$hostikname" -u bla\bla -p $plainpwd cmd /c "del c:\programdata\$program"
}
This is a part of script that we use to remote install programs on out client pc's.
works great only one problem:
script wont continue until it finish each psexec line. the script let the end user install the programs with admin right, it is interactive installation so the user is needed to be on the computer.
if for some reason one user call the script, and then goes for a cofee, script will stay stuck until the user will return and continue installation.
what i'd like to do is a check up - if for some reason one of the psexec lines is taking more than 2 minutes, id like to exit break break the psexec part and continue code.
how can i achive this?
As Abraham mentioned Start-Job is a viable solution to your problem. Using Start-Job will allow you to start and monitor the job's progress/state.
$allowedSecondsForCompletion = 120
foreach ($program in $programlist) {
"$line installed $program" | Out-File "$logpath\log.txt" -Append
$timer = [System.Diagnostics.Stopwatch]::StartNew()
$job = Start-Job -ScriptBlock {
psexec \\"$hostikname" -u bla\bla -p $plainpwd cmd /c "pushd $BucketPath & copy $program c:\programdata\"
psexec \\"$hostikname" -i -u bla\bla -p $plainpwd -h cmd /c "c:\programdata\$program"
psexec \\"$hostikname" -u bla\bla -p $plainpwd cmd /c "del c:\programdata\$program"
}
while ($job.state -eq 'Running' -and $timer.ElapsedMilliseconds -lt ($allowedSecondsForCompletion * 1000))
{
start-sleep -Seconds 5
}
if ($job.State -ne 'Completed') {
# check and Log failure
# Terminate job if still running
$job | Remove-Job -Force
# or $job.StopJob()
}
}
When I run this command locally on a remote machine it works:
powershell -Command "(New-Object Net.WebClient).DownloadFile('<WebPath>', 'C:\Users\<user>\Desktop\file.exe')"
When I try the same command remotely using PsExec in a batch file:
(Set downloadFileCommand = powershell -Command "(New-Object Net.WebClient).DownloadFile('%WebPath%', 'C$\Users\<user>\Desktop\file.exe')")
PsExec.exe \\<remote_machine> -u %username% -p %password% -s -d cmd /c %downloadFileCommand%
I am getting "cmd started on remote_machine with process ID #id_number."
However, nothing happened and the download wasn't executed. The suggestions here:
Run PowerShell scripts on remote PC
didn't work for me.
Any suggestions?
Edit:
I managed to download the file through the command line (in cmd) using this command:
PsExec.exe \\<remote_machine> -u <username> -p <password> -d powershell -Command (New-Object Net.WebClient).DownloadFile('<url address','C:\file.exe')
But it doesn't work when I try this in a batch file:
(Set DownloadInstaller = "powershell -Command (New-Object Net.WebClient).DownloadFile('<url address','C:\file.exe')")
PsExec.exe \\<remote_machine> -u %username% -p %password% -h -d cmd /c %DownloadInstaller%
This worked - all in one line. I have a loop variable, a remote computer (%%a). I assumed that when I use PsExec, C:\ ... \file.exe "thinks" of C:\ locally in the remote computer, but that probably wasn't the case.
I had to write it all in one line, since the path in DownloadFile (The location I want to download the file to) is locally in the remote computer (which is a loop variable):
PsExec.exe \\%%a -u %username% -p %password% -h -d cmd /c powershell.exe -Command "&{ (New-Object System.Net.WebClient).DownloadFile('%url%','\\%%a\C$\Users\<username>\Desktop\%file%')}")
I am running a script on a remote server (windows) using Jenkins:
Invoke-Command -ComputerName myserver -ScriptBlock { D:\DeployScript\myscript.bat } -credential $Cred -ErrorAction Stop
inside this "myscript.bat" i running a psexec command:
psexec -i -h -u myserver\Administrator -p mypassword {mycommands}
how can i tell Jenkins to stop if an error occur on "myscript.bat"
(i must using Psexec because the script require interactive desktop)
Thanks!
In powershell you can get the exit code of the last command using the automatic variable $lastexitcode, so try something like this:
if ($lastexitcode -ne 0) { exit 1 }
or even better:
exit $lastexitcode
I am running the below batch file to connect the remote machine & run a powershell script on the remote machine using psexec.
Running batch file on local machine (myscript.bat)
Running Command: myscript.bat \\mymachine
set machinename=%1
#echo " started"
PsExec.exe %machinename% -u myID -p myPwd -i -d cmd /c mkdir C:\test
xcopy DirChk.ps1 %machinename%\C$\test
psexec.exe %machinename% -u myID -p myPwd cmd.exe /c 'echo .|powershell.exe -file C:\Test\DirChk.ps1'
#echo "Completed"
Error:
Starting PsExec service on \\mymachine ...Processing -File
'C:\Test\DirChk.ps1'' failed because the file does not have a '.ps1'
extension. Specify a valid PowerShell script file name, and then try
again.
Try double quotes. Batch files are interpreted by cmd, which doesn't understand single quotes. This should work:
psexec.exe %machinename% -u myID -p myPwd cmd.exe /c "echo .|powershell.exe -file C:\Test\DirChk.ps1"
I have a string in powershell, which contains a native sqlcmd command. The command itself can be executed successfully in cmd.exe. I have difficulty in executing them in powershell. Anyone can help? Thanks.
This is sql.sql
select ##servername
go
select ##servicename
This is the result when I execute the sqlcmd command from cmd.exe
C:\Users\test>sqlcmd -S "(local)\instance1" -U a -P a -i "c:\temp\sql.sql"
--------------------------------------------------
thesimpsons\INSTANCE1
(1 rows affected)
--------------------------------------------------
INSTANCE1
(1 rows affected)
C:\Users\test>
This is the powershell script to call the sqlcmd command.
$sql = #"
sqlcmd -S "(local)\instance1" -U a -P a -i "c:\temp\sql.sql"
"#
Invoke-Command $sql
When I execute this powershell script, I got the following error.
PS C:\TEMP> $sql = #"
sqlcmd -S "(local)\instance1" -U a -P a -i "c:\temp\sql.sql"
"#
Invoke-Command $sql
Invoke-Command : Parameter set cannot be resolved using the specified named parame
ters.
At line:5 char:15
+ Invoke-Command <<<< $sql
+ CategoryInfo : InvalidArgument: (:) [Invoke-Command], ParameterBin
dingException
+ FullyQualifiedErrorId : AmbiguousParameterSet,Microsoft.PowerShell.Commands
.InvokeCommandCommand
To call a Win32 executable you want to use the call operator & like this:
& sqlcmd -S "(local)\instance1" -U a -P a -i "c:\temp\sql.sql"
You could also stop using the external 'SQLCMD.EXE' and use the Invoke-Sqlcmd cmdlet instead:
Invoke-Sqlcmd is a SQL Server cmdlet that runs scripts that contain statements from the languages (Transact-SQL and XQuery) and commands that are supported by the sqlcmd utility
Just open the 'sqlps' utility and run
Invoke-Sqlcmd -InputFile "C:\temp\sql.sql"
Please see Running SQL Server PowerShell
You can also load the SQL Server snap-ins manually in PowerShell before using 'Invoke-Sqlcmd';
for MS SQL Server 2012 you can do that by running
Import-Module SqlPs
This is how I build some externals command in my scripts
$scriptblock = {fullpath\sqlcmd -S `"(local)\instance1`" <# comment option -S #>`
-U a `
-P a `
-i `"c:\temp\sql.sql`" }
Invoke-Command -ScriptBlock $scriptBlock
You can then use $args variable inside it and even start it remotly.
$scriptblock = {fullpath\sqlcmd -S `"(local)\instance1`" <# comment option -S #>`
-U a `
-P a `
-i `"$($args[0])`" }
Invoke-Command -ScriptBlock $scriptBlock -argumentList "c:\temp\sql.sql" -computer "remote1"
Remark :
This allow to comment each param.
Be careful not to forget a "`" and no space after them where they are at the end of the line.
Use Invoke-Expression rather than Invoke-Command
The first positional parameter of invoke-command is -scriptblock, and it expects a script block argument. To take advantage of a here-string to build the command and then run it with invoke-command, you need to convert the here-string to a script block:
$sql = #"
sqlcmd -S "(local)\instance1" -U a -P a -i "c:\temp\sql.sql"
"#
Invoke-Command ([scriptblock]::create($sql))
Both instance name and username should be fully qualified
<domain_name>\Instanc_name and <domai_name>\Username. Only your instance name is correctly scripted.
This is what worked for me for using sqlcmd from within the powershell script using the & operator, see sample to generate a csv file:
& cmd /c "sqlcmd -S $sv -i $PROCFILE -s, -v varDB = $dbclean -o $filename"
$sv has server name like SERVERNAME\INSTANCE
$PROCFILE is like d:\TSTSQL\Sqlquery.SQL
$filename is d:\TSTSQL\Desiredoutfilename.CSV
$dbclean is a parameter passed to the sql file