I'm using PSRemoting with the WebAdministration module to get info about various sites, and it's working. I am, however, receiving an annoying non-fatal COM exception during invocation of the command, and wondering if anyone else has resolved it. Here's a minimal implementation:
cls
$command = {
param($alias)
Import-Module 'WebAdministration'
$binding = Get-WebBinding -HostHeader $alias
$binding
}
$server = 'server'
$args = #('alias')
$session = New-PSSession -ComputerName $server
Write-Host ("Invoking")
try {
Invoke-Command -Session $session -ScriptBlock $command -ArgumentList $args
Write-Host ("Invoked")
} catch {
Write-Host ("Caught $_")
} finally {
Write-Host ("Removing")
Remove-PSSession -Session $session
Write-Host ("Removed")
}
And here are the results:
Invoking
protocol : http
bindingInformation : 10.x.x.x:80:alias
...
Schema : Microsoft.IIs.PowerShell.Framework.ConfigurationElementSchema
An unhandled COM interop exception occurred: Either the application has not called WSAStartup, or WSAStartup failed. (Exception from HRESULT: 0x800
7276D)
+ CategoryInfo : InvalidOperation: (:) [], RuntimeException
+ FullyQualifiedErrorId : COMException
Invoked
Removing
Removed
I observe the result is returned prior to the error being thrown.
Amusing details:
- Get-Website, Get-Item "IIS:\...", Get-WebBinding all result in the same error
- Running $command directly on the target machine as written results in no error
- Get-Item "d:\..." does not result in any error
- The COM error doesn't
I was able to work around the issue using the following:
$iisIpAddresses = Invoke-Command -Session $session -scriptblock {
if (!(Get-Module WebAdministration))
{
Import-Module WebAdministration
}
$iisBindings = Get-WebBinding
[String[]]$iisBindings = $iisBindings | Select bindingInformation
$iisBindings
}
Remove-PSSession $session
This is buried somewhere deep in the bowels of PowerShell's implementation of .NET and winsock. It's below anything I can calibrate, so I've added " -ErrorAction SilentlyContinue" to my remote invoke. It doesn't fix anything, but everything works correctly. That's answer enough for now, I guess.
Related
I created a short PowerShell scrtipt in order to import a .reg file (an ODBC) to another server session.
I faced to this warning/issue.
The message is this (below):
The operation completed successfully.
+ CategoryInfo : NotSpecified: (The operation completed successfully.:String) [], RemoteException
+ FullyQualifiedErrorId : NativeCommandError
+ PSComputerName : MYSERVERNAME
NotSpecified: (:) [], RemoteException
The script, install without problem the .reg file, but constantly I get the message.
This is my code:
#PARAMETERS - Variables
$Serverlist = Get-Content C:\ServerList.txt
try
{
Foreach ($ServerName in $Serverlist)
{
$session = New-PSSession -ComputerName $servername
Write-Host -Foregroundcolor Green "Copying ODBC Driver for $servername"
$copy_cmd = "C:\MYFILE.reg"
Copy-Item $copy_cmd \\$servername\C$\ -recurse -force;
Write-Host -Foregroundcolor Green "ODBC Successfully copied on $servername"
#$session = New-PSSession -ComputerName $servername
Invoke-Command -Session $session -ScriptBlock {
#Start-Process
reg import C:\CopiedFile.reg #This line generate the message
Write-Host -Foregroundcolor Green "ODBC was installed
}
catch
{
Write-Host "ERROR" -Foregroundcolour Red
exit
}
I tried to incapsulate the Invoke-Command or reg import in to try - catch statement, but the message still appear. I used another command, instead reg import, but the nothing change.
I can use this command line, but I would like to catch the error.
Write-Host -Foregroundcolor Green "ODBC is installed " } ##-ErrorAction SilentlyContinue
There is any way to get the eventually error or handle the message.
Thanks in advance.
If the try block does not generate a terminating error, it will not move into the Catch block. This is controlled by -ErrorAction parameter. So you can set
Invoke-Command Session $session -ScriptBlock {} -ErrorAction Stop
This will cause the Invoke-Command Cmdlet to generate terminating errors(if any error occurs) allowing catch block to execute.
Below is a simple script block, the script block works. However, I would like to suppress any errors that the script block would generate.
$Name = 'TEST'
$SB = { param ($DSNName) ;
$conn = new-object system.data.odbc.odbcconnection
$conn.ConnectionString = ('DSN='+ $DSNName)
$conn.open()
$ConState = $conn.State
$conn.Close()
$ConState
}
$test = Start-job -scriptblock $SB -args $Name -RunAs32 -ErrorAction Stop | wait-job | receive-job
What I am trying to get out of this is a simple test for a 32bit ODBC connection. If the connection fails the connection state will remain closed but I also get an exception error I would like to suppress
Exception calling "Open" with "0" argument(s): "ERROR [IM002] [Microsoft][ODBC Driver Manager] Data source name not found and no default driver specified"
+ CategoryInfo : NotSpecified: (:) [], MethodInvocationException
+ FullyQualifiedErrorId : OdbcException
+ PSComputerName : localhost
If I pipe to out-null my $test variable is empty. When I use a valid DSN Name everything works as desired.
You could use try..catch:
try {
$test = Start-job -scriptblock $SB -args $Name -RunAs32 -ErrorAction Stop | wait-job | receive-job
catch [System.Management.Automation.MethodInvocationException] {
# Do nothing here if you want to suppress the exception completely.
# Although redirecting it to a log file may be a better idea, e.g.
# $Error[0] | Out-File -FilePath "script.log"
}
I am unable to run an invoke-command script to install printers on a remote machine. My code works locally, but as soon as I pipe it into Invoke-command, i get errors.
Local:
$Printer = "\\server1\printer1"
(New-Object -Com Wscript.Network).AddWindowsPrinterConnection($Printer)
And this adds the printer just fine. I can do this same command on the remote computer with no issues. But when i tried to execute the command remotely I have the issues.
Remote:
$compname = "computer"
$Printer = "\\server1\printer1"
Invoke-Command -ComputerName $CompName -Scriptblock {(New-Object -Com Wscript.Network).AddWindowsPrinterConnection('$Printer')}
Which returns the error "The printer name is invalid"
So I tried to see what the shell was sending to the remote computer with the following code, and everything in the write output looks good, but I still get errors:
Invoke-Command -ComputerName $CompName -Scriptblock {(New-Object -Com Wscript.Network).AddWindowsPrinterConnection('$Printer'); write-host "(New-Object -Com Wscript.Network).AddWindowsPrinterConnection('$Printer')"}
Output:
Exception calling "AddWindowsPrinterConnection" with "1" argument(s): "The printer name is invalid. (Exception from
HRESULT: 0x80070709)"
+ CategoryInfo : NotSpecified: (:) [], MethodInvocationException
+ FullyQualifiedErrorId : ComMethodTargetInvocation
+ PSComputerName : computer
(New-Object -Com Wscript.Network).AddWindowsPrinterConnection('\\server1\printer1')
Edit 1/5/2015
So I've tried Paul's code with a number of different entries to the argumentlist. All have not worked so far. i think the first 3 are closer to an answer.
-ArgumentList ""\\server1\printer1""
-ArgumentList ""'\\server1\printer1'""
-ArgumentList "\"\\server1\printer1""
Results in:
Invoke-Command : A positional parameter cannot be found that accepts argument '\\server1\printer1'.
At line:1 char:1
+ Invoke-Command -ComputerName $CompName -Scriptblock {(New-Object -Com Wscript.Ne ...
+ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ CategoryInfo : InvalidArgument: (:) [Invoke-Command], ParameterBindingException
+ FullyQualifiedErrorId : PositionalParameterNotFound,Microsoft.PowerShell.Commands.InvokeCommandCommand
-ArgumentList "'\\server1\printer1'"
-ArgumentList \'"\\server1\printer1"'
-ArgumentList \""\\server1\printer1""
-ArgumentList \"\\server1\printer1"
Result in:
Exception calling "AddWindowsPrinterConnection" with "1" argument(s): "The printer name is invalid. (Exception from
HRESULT: 0x80070709)"
+ CategoryInfo : NotSpecified: (:) [], MethodInvocationException
+ FullyQualifiedErrorId : ComMethodTargetInvocation
+ PSComputerName : sso-mxl327082y
Try this:
Invoke-Command -ComputerName $CompName -Scriptblock {(New-Object -Com Wscript.Network).AddWindowsPrinterConnection($args[0]); write-host "(New-Object -Com Wscript.Network).AddWindowsPrinterConnection($($args[0]))"} -ArgumentList "\\server1\printer1"
I think it´s because your $printer variable is placed between single quotes, variables between single quotes are not interpreted by powershell. So the printername your function probably gets is "$printer".
In case you wonder it is printed out correctly in your write-host statement because here the single quotes are inside a string.
you need to use $Using:yourvar to pass variables to the scriptblock
$compname = "computer"
$Printer = "\\server1\printer1"
Invoke-Command -ComputerName $CompName -Scriptblock
{
(New-Object -Com Wscript.Network).AddWindowsPrinterConnection($Using:$Printer)
}
I think it's because of the so called 'double hop problem', where your authentication isn't transfered to the next remote computer which is sharing the printer.
I tried to solve similar problem using add-printer and following this article double hop problem solution.
However, although it works with get-childitem etc. it doesn't work with add-printer cmdlet.
I have very simple powershell script that starts service remotely.
Invoke-Command -Session $session -ScriptBlock { Start-Service "My test service v1" }
works fine but
$myval="My test service v1"
Invoke-Command -Session $session -ScriptBlock { Start-Service $myval }
fails with
Cannot validate argument on parameter 'InputObject'. The argument is
null or empty. Supply an argument that is not null or empty and then
try the command again.
+ CategoryInfo : InvalidData: (:) [Start-Service], ParameterBindingValidationException
+ FullyQualifiedErrorId : ParameterArgumentValidationError,Microsoft.PowerShell.Commands.StartServiceCommand
+ PSComputerName : mdfiletest
To me they are the same. Why is this not working? thanks
It does not work because when the scriptblock is executed on the remote server, the variable $myval does not exist in session state; it only exists on the local (client) side. The powershell v2/v3 compatible way to do this is:
invoke-command -session $session -scriptblock {
param($val); start-service $val } -args $myval
Another powershell v3 (only) way is like this:
invoke-command -session $session -scriptblock { start-service $using:myval }
The $using prefix is a special pseudo-scope which will capture the local variable and try to serialize it and send it remotely. Strings are always serializable (remotable.)
I am trying to install a service on a remote machine using the powershell.
So far I have the following:
Invoke-Command -ComputerName $remoteComputerName -ScriptBlock {
param($password=$password,$username=$username)
$secpasswd = ConvertTo-SecureString $password -AsPlainText -Force
$credentials = New-Object System.Management.Automation.PSCredential ($username, $secpasswd)
New-Service -Name "XXX" -BinaryPathName "c:\XXX.exe" -DisplayName "XXX XXX XXX" -Description "XXXXXX." -Credential $credentials -ErrorVariable errortext
Write-Host("Error in: " + $errortext)
} -ArgumentList $password,$username -ErrorVariable errortext
Write-Host("Error out: " + $errortext)
When there is an error while executing New-Service the $errortext ErrorVariable get set properly inside the ScriptBlock, because the text: "Error in: shows me the error.
The ErrorVariable of the Invoke-Command does not get set (which I expected).
My question is:
Is it somehow possible to set the ErrorVariable of the Invoke-Command to the error I got inside the ScriptBlock?
I know I could also use InstalUtil, WMI and SC to install the service, but this is not relevant at the moment.
No, you can't get the Errorvariable from the Invoke-Command call to be set the same as in the scriptblock.
But if your goal is "detect and handle errors in the scriptblock, and also get errors returned back to the context of the Invoke-Command caller" then just do it manually:
$results = Invoke-Command -ComputerName server.contoso.com -ScriptBlock {
try
{
New-Service -ErrorAction 1
}
catch
{
<log to file, do cleanup, etc>
return $_
}
<do stuff that should only execute when there are no failures>
}
$results now contains the error information.
The Invoke-Command argument list is a one way deal. You can either output the error variable in the script e.g. on the last line of the scriptblock put:
$errortext
or better yet, just don't capture the error via the -ErrorVariable at all. The scriptblock output, including errors, will flow back to the caller even over a remote connection.
C:\> Invoke-Command -cn localhost { Get-Process xyzzy } -ErrorVariable errmsg 2>$null
C:\> $errmsg
Cannot find a process with the name "xyzzy". Verify the process name and call the cmdlet again.
+ CategoryInfo : ObjectNotFound: (xyzzy:String) [Get-Process], ProcessCommandException
+ FullyQualifiedErrorId : NoProcessFoundForGivenName,Microsoft.PowerShell.Commands.GetProcessCommand
+ PSComputerName : localhost
In general, I think it is much better to keep errors on the error stream, separated from the normal output.
This is almost certainly not the "correct" answer, but this is what I use when I want Invoke-Command to throw an error in the script.
$error.Clear()
Invoke-Command -ComputerName localhost -ScriptBlock {Command-ThatFails}
if ($error.Count -gt 0) { throw $error[0] }
If you wanted to keep the error in a variable, you could do the following:
$error.Clear()
Invoke-Command -ComputerName localhost -ScriptBlock {Command-ThatFails}
if ($error.Count -gt 0) { $myErrorVariable = $error[0] }
In the strictest sense, I believe the answer is no, you cannot set Invoke-Command's ErrorVariable to the contents of the ErrorVariable inside the script block. The ErrorVariable is only for the command it's attached to.
However, you can pass the variable in the script block out to Invoke-Command's scope. In your code you run your New-Service command with -ErrorVariable errortext. Instead, create your variable in the 'script' scope by prefacing the variable name with "script:", like this: -ErrorVariable script:errortext. That makes the variable available outside of the script block as well as inside.
Now your final line Write-Host("Error out: " + $errortext) will output the error that was generated inside of the script block.
More information here and here.