Reputation: 542
I am building a dashboard (WinForm) for internal usage, written in PS, and have a section where users can query sites using various methods/tools for inspection.
All the other methods/tools (IWR, nslookup via CMD call, OpenSSL via CMD call, CURL via CMD call, etc.) have no issues displaying their query results within a Form TextBox... and results for CURL commands seem to execute, return and save results properly in a PS string variable fine when run just within PS (see demo), but when running from the Form, PS seems to want console input for some reason and never displays the stored string in the Form (I presume because it isn't populating the same when called from the Form).
To minimally reproduce the issue, here is the code...
[void] [System.Reflection.Assembly]::LoadWithPartialName("System.Drawing")
[void] [System.Reflection.Assembly]::LoadWithPartialName("System.Windows.Forms")
[void] [System.Windows.Forms.Application]::EnableVisualStyles()
$Form = New-Object system.Windows.Forms.Form
$Form.Size = New-Object System.Drawing.Size(600,880)
$form.MaximizeBox = $false
$Form.StartPosition = "CenterScreen"
$Form.FormBorderStyle = 'Fixed3D'
$Form.Text = "Query Dashboard"
$Font = New-Object System.Drawing.Font("Arial",9,[System.Drawing.FontStyle]::Bold)
$form.Font = $Font
#####RESULTSBOX and OUTPUT BUTTONS####
$Results_txtbox = New-Object System.Windows.Forms.RichTextBox
$Results_txtbox.Multiline = $true
$Results_txtbox.ScrollBars = "Vertical"
$Results_txtbox.Location = New-Object System.Drawing.Size(10,490)
$Results_txtbox.Size = New-Object System.Drawing.Size(485,270)
$Form.Controls.Add($Results_txtbox)
##########CURL#############
#divider
$CURLLinediv = New-Object System.Windows.Forms.Label
$CURLLinediv.Text = ""
$CURLLinediv.BorderStyle = "Fixed3D"
$CURLLinediv.AutoSize = $false
$CURLLinediv.height = 2
$CURLLinediv.width = 550
$CURLLinediv.Location = New-Object System.Drawing.Size(20,340)
$Form.Controls.Add($CURLLinediv)
$LabelCURL = New-Object System.Windows.Forms.Label
$LabelCURL.Text = "CURL"
$LabelCURL.AutoSize = $true
$LabelCURL.Location = New-Object System.Drawing.Size(30,342)
$Form.Controls.Add($LabelCURL)
$CURL_query_txtbox = New-Object System.Windows.Forms.TextBox
$CURL_query_txtbox.Location = New-Object System.Drawing.Size(20,360)
$CURL_query_txtbox.Size = New-Object System.Drawing.Size(300,20)
$CURL_query_txtbox.Text = "-s www.google.ca"
$CURL_query_txtbox.add_MouseHover($CURLquery_Help)
$Form.Controls.Add($CURL_query_txtbox)
$CURL_query_tip = New-Object System.Windows.Forms.ToolTip
$CURLquery_Help ={ $tip = "Enter entire CURL CMD here starting after curl"
$CURL_query_tip.SetToolTip($this,$tip)
}
$CURL_button = New-Object System.Windows.Forms.Button
$CURL_button.Location = New-Object System.Drawing.Size(325,355)
$CURL_button.Size = New-Object System.Drawing.Size(40,22)
$CURL_button.Text = "GET"
$CURL_button.Add_Click({CURL})
$Form.Controls.Add($CURL_button)
function CURL
{
#MOCK
#$CURL_query_txtbox.Text = "-s www.google.ca"
###$Results_txtbox.Text = (curl.exe $($CURL_query_txtbox.Text) 2>&1 | % ToString) -join "`n"
###$Results_txtbox.Text = (curl.exe -s www.google.ca 2>&1 | % ToString) -join "`n"
$Results_txtbox.Text = Invoke-Expression "curl.exe $($CURL_query_txtbox.Text) 2>&1"
}
$result = $Form.ShowDialog()
If you hit the GET button, the results should show in the Results textbox, but instead of returning the result to the form, PS wants an IWR parameter (if you enter www.google.ca or another Uri, it will return back to the application but does nothing with the input, and doesn't update the textfield... but you can now close the Form.
Now if in your PS window you run
$Results_txtbox.Text = (curl.exe -s www.google.ca 2>&1 | % ToString) -join "`n"
you can see that it populates $Results_txtbox.Text
correctly when running from PS, and if you mock (ie - $CURL_query_txtbox.Text = "-s www.google.ca"
) first, you will see that
$Results_txtbox.Text = Invoke-Expression "curl.exe $($CURL_query_txtbox.Text) 2>&1"
works perfectly in PS alone, but when called from the Form it doesn't return any results, and the same cmdlet Invoke-WebRequest..
. message shows up in the PS console looking for a parameter to be entered.
Upvotes: 2
Views: 1200
Reputation: 438178
The error message suggests that you accidentally called the curl
alias, which is Windows PowerShell's built-in alias for the Invoke-WebRequest
cmdlet (note that PowerShell [Core] 7+ no longer has this alias).
Even though you meant to call your custom CURL
function, the built-in alias took precedence, because aliases have higher precedence than functions - see about_Command_Precedence.
A simple solution is to give your function a different name.
Also, you don't need cmd.exe
to make your curl.exe
call:
$Results_txtbox.Text = (curl.exe -s www.google.ca 2>&1 | % ToString) -join "`n"
If the target command - curl.exe -s www.google.ca
- comes from a text box filled by the user and you trust that input, use Invoke-Expression
, though note that, in general, it should be avoided.
$Results_txtbox.Text = (
Invoke-Expression "$($CURL_query_txtbox.Text) 2>&1" | % ToString
) -join "`n"
If only the arguments come from the text box:
Invoke-Expression "curl.exe $($CURL_query_txtbox.Text) 2>&1" | % ToString
Note:
% ToString
(short for: ForEach-Object { $_.ToString() }
) is only needed in Windows PowerShell, to ensure that stderr lines - which PowerShell wraps in ErrorRecord
instances - are represented as-is in a string context - this is no longer necessary in PowerShell [Core] 7+.
-join "`n"
(or -join [Environment]::NewLine
, if you want to use the platform appropriate newline [sequence], though that is usually not necessary) is used to join the array of output lines to form a single, multi-line string; while piping to Out-String
works similarly, it - unfortunately - always adds a trailing newline.
Out-String
's behavior is discussed in GitHub issue #14444.Also note that the stream-merging redirection, 2>&1
, is embedded in the string passed to Invoke-Expression
.
One would expect the following form to work as well:
Invoke-Expression $CURL_query_txtbox.Text 2>&1
However, as of PowerShell 7.1 it does not; this unexpected behavior is discussed in GitHub issue #14503.
Upvotes: 2