I'm using Powershell on Win 2008r2 to make a remote call to msiexec as follows:
Invoke-Command -session $Session -ScriptBlock{param($arguments) start-process -FilePath "msiexec.exe" -Wait $arguments } -Argument $arguments
Currently I'm checking for success using if(!$?) but this is no good because I've just seen the msiexec process throw a 1638 error (because the app is already installed on the remote server) but the value of $? was True.
Can anyone please tell me how I can capture the 1638 code, or whatever else, is returned by msiexec on the remote server?
Thanks, Rob.
This was a very hackish way to do this, but I got around this by using a global-like variable in terms of $script:functionexitcode which I would assign with the value of the .ErrorCode from the msiexec.exe using Start-Process.
Then in the main part of the PowerShell script, I would test that value if ($functionexitcode -eq 0).
Here is the full snippet from a very similar install scenario with Start-Process:
# Start MSP upgrade to UR
$upgrade = (Start-Process -Filepath $msiexecpath -ArgumentList $argumentlist_BEGIN$argumentlist_MSP$argumentlist_END -PassThru -Wait -ErrorAction Stop)
if ($upgrade.ExitCode -eq 0) {
Write-Host "Upgrade successful. Error code:" $upgrade.ExitCode `
"`nUpgrade logfile location: " $workingdirectory\$msi_logfile_upgrade
$script:FunctionExitCode = $upgrade.ExitCode
Related
Background: I am creating a script to send out a message to everyone in my Domain. I was able to complete this using Invoke-WMImethod and MSG.exe. However, my supervisor wants a more customizable message to be sent. Like changing Color, font size, font style...etc. Which i have created using PowerShell.
Script:
Invoke-WmiMethod -ComputerName $Computer -Class Win32_Process -Name Create -ArgumentList {"C:\x\x\x\Powershell.exe -File `"\\Server\Share\Folder\Script.ps1`""}
When i run this script against my Computer it works perfectly. However, when i attempt to run it on a remote computer it fails.
I don't understand why.
It's the same exact script that i used with MSG.exe, which worked, but it still doesn't work with a powershell script.
I attempted to copy the script to the remote computers 'C:\' and run it from that file path but it still didn't work.
I've verified the file path to Powershell.exe is the same as the script and that the remote workstation can access the .PS1 Script.
However, the script does run and says it is successful with a Return Value of 0. Example:
__GENUS : 2
__CLASS : __PARAMETERS
__SUPERCLASS :
__DYNASTY : __PARAMETERS
__RELPATH :
__PROPERTY_COUNT : 2
__DERIVATION : {}
__SERVER :
__NAMESPACE :
__PATH :
ProcessId : 8748
ReturnValue : 0
My Suggestion would be to check for the versions on both the machines. The CmdLet you using may not be working on the previous version.
I again have a suggestion to make, you can use the below command to get your work done, if you have powershell Version 3 or above.
$Outputreport = "Test message to send data using port 443"
[System.Net.ServicePointManager]::ServerCertificateValidationCallback = { $true }
$wc = new-object System.Net.WebClient
Invoke-RestMethod -Method Post https://hostnamedotcom/cgi-bin/dir-path/$hostname-filename -Body $Outputreport
I have written the following script for SQL patching:
cls
$computers = Get-Content D:\Abhi\Server.txt
foreach ($line in $computers)
{
psexec \\$line -s -u Adminuser -p AdminPassword msiexec /i D:\SQL_PATCH\rsSharePoint.msi SKIPCA=1 /qb
}
My doubt here is to parallelize this script execution on all the servers mentioned in the text file. Meaning, as soon I start the execution of the script, this should initiate the patching activity on the servers simultaneously and also to track the progess on all the servers, as this script is doing now only for one server.
Kindly help me on this.
Thanks Ansgar Wiechers.
This piece of code did it. It helps in executing the .exe simultaneously on all the servers as well as track their status:
cls
$servers = Get-Content 'D:\Abhi\Server.txt'
$servers | ForEach-Object {$comp = $_
Start-Job -ScriptBlock {psexec \\$input -s -u Adminuser -p AdminPassword C:\SQL_PATCH\SQLServer2008R2SP3-KB2979597-x64-ENU.exe /quiet /action=patch /allinstances /IAcceptSQLServerLicenseTerms} -InputObject $comp}
While (Get-Job -State Running)
{
Get-Job | Receive-Job
#Start-Sleep 2
#Write-Host "Waiting for update removal to finish ..."
}
Remove-Job *
I am extreme newbie to powershell. I have a script that I want to pass a URL as a parameter. The url runs a PHP process that creates and downloads a PDF file then the script prints the pdf and then deletes the pdf. I cannot get the URL parm to work.
Below is my script
$w=$args[0]
Start $w
$Directory = "C:\Users\pslessor\downloads\"
Get-ChildItem -path $Directory -recurse -include *.pdf | ForEach-Object {Start-Process -FilePath $_.fullname -Verb Print -PassThru | %{sleep 5;$_} | kill }
Remove-Item C:\Users\pslessor\downloads\* -include *.PDF
This script is being executed by a batch file PrintPl.bat
SET ThisScriptsDirectory=%~dp0
SET PowerShellScriptPath=%ThisScriptsDirectory%PrintPl.ps1
PowerShell -NoProfile -ExecutionPolicy Bypass -Command "& '%PowerShellScriptPath%' %1";
And I am testing with testprint.bat
C:\Wget\PrintPl "https://partners.wayfair.com/print_shipping_docs.php?Print=1&printPackingSlips=1&PackingSlipPOs=CS287851107"
The URL is all in one string this editor is forcing the line feed at .php?
The Error I am getting is
The string starting:
At Line:1 Char:25
+ & 'C:\Wget\Printpl.ps1' <<<< 'https://partners.wayfair.com/print_shipping_docs.php?print;
is missing the terminator: '.
At line:1 Char:85
+ & 'C:\Wget\PrintPl.psl' 'https://partners.wayfair.com/print_shipping_docs.php
?print; <<<<
+ CategoryInfo :ParserError: <https://partner...docs.php?print;:
String> [], ParentContainsErrorRecordException
+ FullyqualifiedErrorid : TerminatorExpectedAtEndOfString
'printPackingSlips' is not recognaized as internal or external command,
Operable program or batch file.
'PackingSlipPOs' is not recognized as an internal or external command,
operable program or batch File
This is happening because when you pass the arguments the command interpreter expands your variables and see this:
PowerShell -NoProfile -ExecutionPolicy Bypass -Command "& 'C:\Wget\PrintPl.ps1' https://partners.wayfair.com/print_shipping_docs.php? Print=1&printPackingSlips=1&PackingSlipPOs=CS287851107"
So the command that it is trying to execute is C:\Wget\PrintPl.ps1, and it assumes that what comes next are arguments. Since what it is passed has a space, and is not enclosed in quotes or double quotes it assumes that it is multiple arguments. It sees it as:
Execute this script: C:\Wget\PrintPl.ps1
With the following arguments:
$Args[0]=?
$Args[1]=Print=1&printPackingSlips=1&PackingSlipPOs=CS287851107
To stop this from happening you will need to enclose the URL in quotes as well, so your command should look like this:
PowerShell -NoProfile -ExecutionPolicy Bypass -Command "& '%PowerShellScriptPath%' '%1'"
Edit: Ok, that didn't work for your case. So we're going to change this a little bit. Instead of -Command I'm going to suggest you use -File. So your Powershell execution line within the batch file will look like this:
PowerShell -NoProfile -ExecutionPolicy Bypass -File "%PowerShellScriptPath%" %*
You should be able to run the batch file exactly as you previously had been. I'm fairly confident that will work for you.
I am looking to execute a command in remote machine using invoke but the .cmd file will call for additional .vbs script. So i guess i may have to mention CScript if so how do i mention both cmd/c and cscript in the below command
Invoke-Command -computername blrscrv01 -ScriptBlock { param($path, $command ) cmd /c $path $command } -args '"C:\windows\system32\cscript.exe"','"/?"'
Your example worked for me when I removed the extra level of quoting.
Invoke-Command -computername blrscrv01 -ScriptBlock { param($path, $command ) cmd /c $path $command } -args 'C:\windows\system32\cscript.exe','/?'
Troubleshooting
Enter a remote session and poke around.
Enter-PSSession -computername blrscrv01
Verify that the target script exists and is accessible.
dir \\lcsap027\deploy\c2.cmd
dir \\lcsap027\deploy
type \\lcsap027\deploy\c2.cmd
Attempt to run the script interactively.
\\lcsap027\deploy\c2.cmd
or
cmd /c \\lcsap027\deploy\c2.cmd
Alternative
Another thing you might try is not invoking a cmd script remotely, but issuing the commands remotely. New-PSSession will return a handle you can use to deal interactively with the remote machine. You can repeatedly issue commands with Invoke-Command and get the results (as primitive data types and generic objects, though, not the actual objects themselves).
Altered Script
Here's an altered version of the script you put in your comment. I've removed the nested Invoke-Command (I don't know why it was necessary, you're already running commands on the remote machine). Since the line breaks got lost in the comment, I don't know if there were any statement separator problems (I'll just assume there weren't, though in its "formatted" form as a one-liner, it would have died horribly because PoSH wouldn't have known where one statement ended and the next began).
param(
[string]$ComputerName,
[string]$User,
[string]$pass
)
Get-PSSEssion | Remove-PSSession
$session = New-PSSession -ComputerName $ComputerName
Invoke-Command -Session $session -ScriptBlock {
param(
[string]$ComputerName,
[string]$Username,
[string]$Password
)
$net = new-object -ComObject WScript.Network
$net.MapNetworkDrive("x:", "\\machinename\sharename", $false, $Username, $Password)
cmd.exe /c "x:\c2.cmd"
$net.RemoveNetworkDrive("x:")
} -args $ComputerName, $User, $pass
This at least got the remote script to run and produced the expected output. (I emitted the computer name, user name, and file location.)
Bear in mind that this method doesn't employ any transport-/application-layer encryption, so the password is sent cleartext over the network.
I'm trying to register an OCX file on a remote machine using Powershell 2.0.
This doesn't doesn't work:
$LocalOCXPath = "C:\Windows\SysWOW64\dxapi.ocx"
Invoke-Command -ComputerName $ComputerName -ScriptBlock { "C:\windows\system32\Regsvr32.exe $args" } -argumentlist $LocalOCXPath
But this does:
Invoke-Command -ComputerName $ComputerName -ScriptBlock { & 'regsvr32.exe' 'C:\Windows\SysWOW64\dxapi.ocx' }
I really need to be able to pass the path in via a variable, but I don't think I can do that using option 2. And I have no idea why option 1 doesn't work. By doesn't work, I mean that powershell looks like it invokes the command properly, but when I look on the remote machine, the ocx file isn't registered.
I think you are overenginnering, try:
$LocalOCXPath = "C:\Windows\SysWOW64\dxapi.ocx"
Invoke-Command -ComputerName $ComputerName -ScriptBlock { & 'regsvr32.exe' $LocalOCXPath }
Invoke-Command runs the scriptblock in the context of the remote system so your $LocalOCXPath variable doesn't exist there. In PowerShell 3.0 you can force the variable to be seen in the remote context by prefixing it with $Using:, as in $Using:$LocalOCXPath.