I'm converting my current backup solution for our whole environment to Powershell GUI application. My script is working as intended but now I'm trying to display the output to my GUI textbox field.
The output I'm trying to display is inside a function that's calling an Invoke-Command
scriptblock.
Here's a snipped of my code:
function ZipFiles {
Invoke-Command -ComputerName $servers -ScriptBlock {
# Store the server name in a variable
$hostname = hostname
# Specify the 7zip executable path
$7zipPath = "$env:ProgramFiles\7-Zip\7z.exe"
# Throw an error if 7zip is not installed on the server
if (-not (Test-Path -Path $7zipPath -PathType Leaf)) {
throw "7 zip file '$7zipPath' not found on $hostname"
$7zipInstalled = $false
}
# Confirm that 7zip is installed on the remote server
else {
$7zipInstalled = $true
Write-Host -ForegroundColor Cyan "7zip found on $hostname. Zipping files..."
I'm importing my layout from a XAML file and my TextBox
item is stored under a variable named
$var_textInfo
. Since this variable is outside my Invoke-Command block, I need to call it with the using:$var_textInfo
syntax.
I tried replacing the Write-Host
line to instead output the result to the textbox using this command:
$using:var_textInfo.AppendText("7zip found on $hostname. Zipping files...")
However, Powershell doesn't seems to let me call methods with the using expression. It throws the following error message:
Expression is not allowed in a Using expression.
Any idea how I could properly output the text from my Invoke-Command
function to my textbox ?
Thanks in advance for your ideas !
I need to call it with the using:$var_textInfo syntax
No, you don't. The Invoke-Command
script block runs on the remote machine(s) and doesn't have access to your local GUI objects. In general, you can't pass live objects to remote scripts, only data that can be serialized.
Instead, pipe Invoke-Command
to ForEach-Object
and update your GUI (locally) from there:
Invoke-Command -ComputerName $servers -ScriptBlock {
# Store the server name in a variable
$hostname = hostname
# Specify the 7zip executable path
$7zipPath = "$env:ProgramFiles\7-Zip\7z.exe"
# Throw an error if 7zip is not installed on the server
if (-not (Test-Path -Path $7zipPath -PathType Leaf)) {
throw "7 zip file '$7zipPath' not found on $hostname"
$7zipInstalled = $false
}
# Confirm that 7zip is installed on the remote server
else {
$7zipInstalled = $true
# Implicit output that can be captured by next pipeline command.
"7zip found on $hostname. Zipping files..."
}
} | ForEach-Object {
# Append text line received from remote script - this code runs locally!
$var_textInfo.AppendText( $_ )
}
To be able to process output of the remote script, you have to write it to the success stream, either using Write-Output
(rarely used) or implicitly, by just writing a string literal on its own line (as I did above). Any command that already outputs to the success stream will also be received by the local ForEach-Object
.