Simple InputBox function - function

I'm aware of a simple pop-up function for PowerShell, e.g.:
function popUp($text,$title) {
$a = new-object -comobject wscript.shell
$b = $a.popup($text,0,$title,0)
}
popUp "Enter your demographics" "Demographics"
But I am unable to find an equivalent for getting a pop-up to ask for input.
Sure, there is Read-Line, but it prompts from the console.
And then there is this complex function, which seems overkill for a script that will ask for input once or twice:
function getValues($formTitle, $textTitle){
[void] [System.Reflection.Assembly]::LoadWithPartialName("System.Drawing")
[void] [System.Reflection.Assembly]::LoadWithPartialName("System.Windows.Forms")
$objForm = New-Object System.Windows.Forms.Form
$objForm.Text = $formTitle
$objForm.Size = New-Object System.Drawing.Size(300,200)
$objForm.StartPosition = "CenterScreen"
$objForm.KeyPreview = $True
$objForm.Add_KeyDown({if ($_.KeyCode -eq "Enter") {$x=$objTextBox.Text;$objForm.Close()}})
$objForm.Add_KeyDown({if ($_.KeyCode -eq "Escape") {$objForm.Close()}})
$OKButton = New-Object System.Windows.Forms.Button
$OKButton.Location = New-Object System.Drawing.Size(75,120)
$OKButton.Size = New-Object System.Drawing.Size(75,23)
$OKButton.Text = "OK"
$OKButton.Add_Click({$Script:userInput=$objTextBox.Text;$objForm.Close()})
$objForm.Controls.Add($OKButton)
$CANCELButton = New-Object System.Windows.Forms.Button
$CANCELButton.Location = New-Object System.Drawing.Size(150,120)
$CANCELButton.Size = New-Object System.Drawing.Size(75,23)
$CANCELButton.Text = "CANCEL"
$CANCELButton.Add_Click({$objForm.Close()})
$objForm.Controls.Add($CANCELButton)
$objLabel = New-Object System.Windows.Forms.Label
$objLabel.Location = New-Object System.Drawing.Size(10,20)
$objLabel.Size = New-Object System.Drawing.Size(280,30)
$objLabel.Text = $textTitle
$objForm.Controls.Add($objLabel)
$objTextBox = New-Object System.Windows.Forms.TextBox
$objTextBox.Location = New-Object System.Drawing.Size(10,50)
$objTextBox.Size = New-Object System.Drawing.Size(260,20)
$objForm.Controls.Add($objTextBox)
$objForm.Topmost = $True
$objForm.Add_Shown({$objForm.Activate()})
[void] $objForm.ShowDialog()
return $userInput
}
$schema = getValues "Database Schema" "Enter database schema"

Probably the simplest way is to use the InputBox method of the Microsoft.VisualBasic.Interaction class:
[void][Reflection.Assembly]::LoadWithPartialName('Microsoft.VisualBasic')
$title = 'Demographics'
$msg = 'Enter your demographics:'
$text = [Microsoft.VisualBasic.Interaction]::InputBox($msg, $title)

The simplest way to get an input box is with the Read-Host cmdlet and -AsSecureString parameter.
$us = Read-Host 'Enter Your User Name:' -AsSecureString
$pw = Read-Host 'Enter Your Password:' -AsSecureString
This is especially useful if you are gathering login info like my example above. If you prefer to keep the variables obfuscated as SecureString objects you can convert the variables on the fly like this:
[Runtime.InteropServices.Marshal]::PtrToStringAuto([Runtime.InteropServices.Marshal]::SecureStringToBSTR($us))
[Runtime.InteropServices.Marshal]::PtrToStringAuto([Runtime.InteropServices.Marshal]::SecureStringToBSTR($pw))
If the info does not need to be secure at all you can convert it to plain text:
$user = [Runtime.InteropServices.Marshal]::PtrToStringAuto([Runtime.InteropServices.Marshal]::SecureStringToBSTR($us))
Read-Host and -AsSecureString appear to have been included in all PowerShell versions (1-6) but I do not have PowerShell 1 or 2 to ensure the commands work identically.
https://learn.microsoft.com/en-us/powershell/module/microsoft.powershell.utility/read-host?view=powershell-3.0

It would be something like this
function CustomInputBox([string] $title, [string] $message, [string] $defaultText)
{
$inputObject = new-object -comobject MSScriptControl.ScriptControl
$inputObject.language = "vbscript"
$inputObject.addcode("function getInput() getInput = inputbox(`"$message`",`"$title`" , `"$defaultText`") end function" )
$_userInput = $inputObject.eval("getInput")
return $_userInput
}
Then you can call the function similar to this.
$userInput = CustomInputBox "User Name" "Please enter your name." ""
if ( $userInput -ne $null )
{
echo "Input was [$userInput]"
}
else
{
echo "User cancelled the form!"
}
This is the most simple way to do this that I can think of.

Related

How do I dynamically insert a string into a text file in PowerShell?

The text is an html file. The line I am interested in looks something like:
<td>INC1234</td><td>INC1235</td><td>INC1236</td>
The INC numbers are different from file to file. I'd like to parse through the line by saying something like:
if like <td>INC, then concatenate '<td><a href="https://www.website.com/=' + INC# + '>"
To give an output like:
<td><a href="https://www.website.com/=INC1234>INC1234</a></td><td><a href="https://www.website.com/=INC1235>INC1235</a></td><td><a href="https://www.website.com/=INC1236>INC1236</a></td>"
EDIT1: Ok, if I do something like:
$parse = (-split (Get-Content -Raw C:\Temp\report.txt) -match '<td>INC')
$parse
It will find the characters, but it will return the entire line rather than looking for more that match the 'INC'. Presumably because they all reside on the same line with no spaces.
EDIT2: Maybe this will help. What I'm doing is using PowerShell to write SQL commands, send it to our SQL Server, return the data and use PSWriteHTML to build the report which works fantastic. But I am wanting the first column, which is the ticket number (eg. INC1234) to be a link to the ticket it reads.
[CmdletBinding()]
Param(
[Parameter(Mandatory=$True)]
[string]$ReportName
)
## Build the query box
function Read-MultiLineInputBoxDialog([string]$Message, [string]$WindowTitle, [string]$DefaultText)
{
Add-Type -AssemblyName System.Drawing
Add-Type -AssemblyName System.Windows.Forms
## Create the Label.
$label = New-Object System.Windows.Forms.Label
$label.Location = New-Object System.Drawing.Size(10,10)
$label.Size = New-Object System.Drawing.Size(280,20)
$label.AutoSize = $true
$label.Text = $Message
## Create the TextBox used to capture the user's text.
$textBox = New-Object System.Windows.Forms.TextBox
$textBox.Location = New-Object System.Drawing.Size(10,40)
$textBox.Size = New-Object System.Drawing.Size(575,200)
$textBox.AcceptsReturn = $true
$textBox.AcceptsTab = $false
$textBox.Multiline = $true
$textBox.ScrollBars = 'Both'
$textBox.Text = $DefaultText
## Create the OK button.
$okButton = New-Object System.Windows.Forms.Button
$okButton.Location = New-Object System.Drawing.Size(415,250)
$okButton.Size = New-Object System.Drawing.Size(75,25)
$okButton.Text = "OK"
$okButton.Add_Click({ $form.Tag = $textBox.Text; $form.Close() })
## Create the Cancel button.
$cancelButton = New-Object System.Windows.Forms.Button
$cancelButton.Location = New-Object System.Drawing.Size(510,250)
$cancelButton.Size = New-Object System.Drawing.Size(75,25)
$cancelButton.Text = "Cancel"
$cancelButton.Add_Click({ $form.Tag = $null; $form.Close() })
## Create the form.
$form = New-Object System.Windows.Forms.Form
$form.Text = $WindowTitle
$form.Size = New-Object System.Drawing.Size(610,320)
$form.FormBorderStyle = 'FixedSingle'
$form.StartPosition = "CenterScreen"
$form.AutoSizeMode = 'GrowAndShrink'
$form.Topmost = $True
$form.AcceptButton = $okButton
$form.CancelButton = $cancelButton
$form.ShowInTaskbar = $true
## Add all of the controls to the form.
$form.Controls.Add($label)
$form.Controls.Add($textBox)
$form.Controls.Add($okButton)
$form.Controls.Add($cancelButton)
## Initialize and show the form.
$form.Add_Shown({$form.Activate()})
$form.ShowDialog() > $null # Trash the text of the button that was clicked.
## Return the text that the user entered.
return $form.Tag
}
## Prompt the SQL Query Box
$Query = Read-MultiLineInputBoxDialog -Message "Enter SQL Query Here" -WindowTitle "SQL Query" -DefaultText "SELECT FROM"
if ($Query -eq $null) { Break }
else { Write-Host "You entered the following text: $Query" }
## Pass query to SQL Server
$Pass = Invoke-Sqlcmd -Query $Query -ServerInstance "MY-SERVER-INSTANCE" -Username "USERNAME" -Password "PASSWORD"
## Output the report and save to the network under the specified name
New-HTML {
New-HTMLTable -EnableColumnReorder -DisableInfo -DataTable $Pass -ExcludeProperty "RowError", "RowState", "Table", `
"ItemArray", "HasErrors" -HideFooter -PagingLength 25 -SearchBuilder
New-HTMLTableStyle -FontFamily Calibri -FontSize 15 -FontStyle normal -TextAlign center -TextColor "#0a0a0a"
New-HTMLTableStyle -FontFamily Calibri -BackgroundColor "#fffdb5" -FontSize 15px -TextColor "#0a0a0a" -TextAlign center -Type RowHover
} -ShowHTML -FilePath "\\Server\$ReportName.html" -Online
The report looks something like:
Ticket: Description:
----------------------------
INC1234 Broken Monitor
INC1235 No Sound
The HTML that PSWriteHTML builds throws all of the ticket numbers on one line so I would like to edit that HTML with the <a href=""> tag to dynamically create links for each ticket # mainly because I don't know how to do it in PS and can't seem to find a good answer through Google - which is why I came here.
Although not familiar with PsWriteHtml, I guess you could simply change the Ticket properties in the array you receive in $Pass:
## Pass query to SQL Server
$Pass = Invoke-Sqlcmd -Query $Query -ServerInstance "MY-SERVER-INSTANCE" -Username "USERNAME" -Password "PASSWORD"
# convert all Tickets into hyperlinks
foreach ($item in $Pass) {
$item.Ticket = '<a href="https://www.website.com/={0}>{0}</a>'-f $item.Ticket
}
Then the rest of your code
## Output the report and save to the network under the specified name
New-HTML {...}

PowerShell run a 'function' (not a script) from a Windows Form add_click

I want to run a defined PowerShell function on an add_click event in a Windows form in that script.
I've found lots of examples of how to call a .ps1 script from a click, but not how to call a function.
Use powershell command in add_click
So, here is my script in full. I am curious on two ways of outputting this information.
• Just open a PowerShell console and show the results in there (the pause will prevent it from closing), or
• In some kind of MessageBox (some more Windows Forms magic or techniques or tooltips, or whatever anyone thinks works well - such techniques are all very interesting to me).
function sysx {
$System = get-wmiobject -class "Win32_ComputerSystem"
$Mem = [math]::Ceiling($System.TotalPhysicalMemory / 1024 / 1024 / 1024)
$wmi = gwmi -class Win32_OperatingSystem -computer "."
$LBTime = $wmi.ConvertToDateTime($wmi.Lastbootuptime)
[TimeSpan]$uptime = New-TimeSpan $LBTime $(get-date)
$s = "" ; if ($uptime.Days -ne 1) {$s = "s"}
$uptime_string = "$($uptime.days) day$s $($uptime.hours) hr $($uptime.minutes) min $($uptime.seconds) sec"
"$Mem GB"
"Up: $uptime_string"
pause
}
# Load Assemblies
Add-Type -AssemblyName System.Windows.Forms
Add-Type -AssemblyName System.Drawing
Add-Type -AssemblyName PresentationFramework # For MessageBox
$MyIcon = [Drawing.Icon]::ExtractAssociatedIcon((Get-Command powershell).Path)
# Create Primary form
$objForm = New-Object System.Windows.Forms.Form
$objForm.Visible = $false
$objForm.WindowState = "minimized"
$objForm.ShowInTaskbar = $false
$objForm.add_Closing({ $objForm.ShowInTaskBar = $False })
$objNotifyIcon = New-Object System.Windows.Forms.NotifyIcon
$objNotifyIcon.Icon = $MyIcon
$objNotifyIcon.Text = "TrayUtility"
$objNotifyIcon.Visible = $true
$objContextMenu = New-Object System.Windows.Forms.ContextMenu
$ToggleMenuItemPS = New-Object System.Windows.Forms.MenuItem
$ToggleMenuItemPS.Index = 1
$ToggleMenuItemPS.Text = "New PowerShell"
if (Test-Administrator) { $ToggleMenuItemPS.Text = "New PowerShell (Admin)" }
$ToggleMenuItemPS.add_Click({
Start-Process PowerShell.exe
})
$ToggleMenuItemFunction = New-Object System.Windows.Forms.MenuItem
$ToggleMenuItemFunction.Index = 2
$ToggleMenuItemFunction.Text = "Mem and Uptime"
$ToggleMenuItemFunction.add_Click({
# some way to call the 'sysx' function in a PowerShell console, MessageBox, tooltip, etc...
})
# Create an Exit Menu Item
$ExitMenuItem = New-Object System.Windows.Forms.MenuItem
$ExitMenuItem.Index = 5
$ExitMenuItem.Text = "E&xit"
$ExitMenuItem.add_Click({
$objForm.Close()
$objNotifyIcon.visible = $false
})
# Add the Menu Items to the Context Menu
$objContextMenu.MenuItems.Add($ToggleMenuItemPS) | Out-Null
$objContextMenu.MenuItems.Add($ToggleMenuItemFunction) | Out-Null
$objContextMenu.MenuItems.Add($ExitMenuItem) | Out-Null
# Assign the Context Menu
$objNotifyIcon.ContextMenu = $objContextMenu
$objForm.ContextMenu = $objContextMenu
# Show the Form - Keep it open
$objForm.ShowDialog() | Out-Null
$objForm.Dispose()
You can just use only sysx there:
$ToggleMenuItemFunction.add_Click({sysx})
To show results in a message box tweak sysx a bit:
$wshshell = new-object -comobject Wscript.shell
$wsh.PopUp("$($Mem) GB`nUp: $($uptime_string)")
All code has scope, even for output. Your function will run, but since you are note telling the output where to go. I added the Test admin function since it was left out of your post.
I tested and validated the below and it works on my system, in a running PowerShell console/ISE/VSCode session. Meaning, it prints this output to the console (of course you can change that to send to a Message Box, et al) and start a new console as admin.
#region Begin code-behind logic
#
function Test-Administrator
{
([Security.Principal.WindowsPrincipal] [Security.Principal.WindowsIdentity]::
GetCurrent()).IsInRole([Security.Principal.WindowsBuiltInRole] "Administrator")
}
function Get-Sysx {
$System = get-wmiobject -class "Win32_ComputerSystem"
$Mem = [math]::Ceiling($System.TotalPhysicalMemory / 1024 / 1024 / 1024)
$wmi = gwmi -class Win32_OperatingSystem -computer "."
$LBTime = $wmi.ConvertToDateTime($wmi.Lastbootuptime)
[TimeSpan]$uptime = New-TimeSpan $LBTime $(get-date)
$s = ""
if ($uptime.Days -ne 1) {$s = "s"}
$uptime_string = "$($uptime.days) day$s $($uptime.hours) hr $($uptime.minutes) min $($uptime.seconds) sec"
"$Mem GB"
"Up: $uptime_string"
pause
}
#
#endregion End code behind logic
#region Begin GUI logic
#
# Load Assemblies
Add-Type -AssemblyName System.Windows.Forms
[System.Windows.Forms.Application]::EnableVisualStyles()
Add-Type -AssemblyName System.Drawing
Add-Type -AssemblyName PresentationFramework # For MessageBox
$MyIcon = [Drawing.Icon]::ExtractAssociatedIcon((Get-Command powershell).Path)
# Create Primary form
$objForm = New-Object System.Windows.Forms.Form
$objForm.Visible = $false
$objForm.WindowState = "minimized"
$objForm.ShowInTaskbar = $false
$objForm.add_Closing({ $objForm.ShowInTaskBar = $False })
$objNotifyIcon = New-Object System.Windows.Forms.NotifyIcon
$objNotifyIcon.Icon = $MyIcon
$objNotifyIcon.Text = "TrayUtility"
$objNotifyIcon.Visible = $true
$objContextMenu = New-Object System.Windows.Forms.ContextMenu
$ToggleMenuItemPS = New-Object System.Windows.Forms.MenuItem
$ToggleMenuItemPS.Index = 1
$ToggleMenuItemPS.Text = "New PowerShell"
if (Test-Administrator) { $ToggleMenuItemPS.Text = "New PowerShell (Admin)" }
$ToggleMenuItemPS.add_Click({
Start-Process PowerShell.exe
})
$ToggleMenuItemFunction = New-Object System.Windows.Forms.MenuItem
$ToggleMenuItemFunction.Index = 2
$ToggleMenuItemFunction.Text = "Mem and Uptime"
$ToggleMenuItemFunction.add_Click({
Get-Sysx | Out-Host
})
# Create an Exit Menu Item
$ExitMenuItem = New-Object System.Windows.Forms.MenuItem
$ExitMenuItem.Index = 5
$ExitMenuItem.Text = "E&xit"
$ExitMenuItem.add_Click({
$objForm.Close()
$objNotifyIcon.visible = $false
})
# Add the Menu Items to the Context Menu
[void]$objContextMenu.MenuItems.Add($ToggleMenuItemPS)
[void]$objContextMenu.MenuItems.Add($ToggleMenuItemFunction)
[void]$objContextMenu.MenuItems.Add($ExitMenuItem)
# Assign the Context Menu
$objNotifyIcon.ContextMenu = $objContextMenu
$objForm.ContextMenu = $objContextMenu
#endregaion End GUI logic
# Show the Form - Keep it open
[void]$objForm.ShowDialog()
$objForm.Dispose()
As for this... [I was hopeful that would work, but using Get-Sysx on its own does nothing.], if you are saying you are not in a PowerShell session when you call this, then that is because you did not start one before the call, so, nothing to write to. So, call a message box instead and the separate call to powershell.exe, and that pause is not needed since the messagebox will stay shown until dismissed.
$ToggleMenuItemFunction = New-Object System.Windows.Forms.MenuItem
$ToggleMenuItemFunction.Index = 2
$ToggleMenuItemFunction.Text = "Mem and Uptime"
$ToggleMenuItemFunction.add_Click({
[System.Windows.Forms.MessageBox]::Show($(Get-Sysx), 'Information', 0)
})

How can you get Powershell to interact with elements on a webpage

I am trying to write a Powershell script that will interact with elements of a webpage. To learn the concepts for the script, I am using Armorgames.com as the target url with my aim to use powershell to log into the site, then make a search of available games according to specified search terms, then export the results to a CSV. The attached code sample is what I currently have. But I'm having trouble understanding which parts of the webpage elements I'm searching for and how to input values into the available fields.
I am also getting the error "Method invocation failed because [mshtml.HTMLDocumentClass] does not contain a method named 'getElementsById'" and I don't understand why
$ie = New-Object -ComObject "InternetExplorer.Application"
$requestUrl = "https://armorgames.com/"
$userId = "username-input";
$passwordId = "password-input"
$signIn = "act"
$ie.visible = $true
#ie.silent = $true
$ie.navigate($requestUrl)
while ($ie.busy) {
Start-Sleep -Milliseconds 100
}
$doc = $ie.Document
$doc.getElementsById("input") | % {
if ($_.id -ne $null){
if ($_.id.Contains($signIn)) { $btn = $_ }
if ($_.id.Contains($passwordId)) { $pwd = $_ }
if ($_.id.Contains($userId)) { $user = $_ }
}
}
$user.value = "ExampleUser"
$pwd.value = "MyPassord"
$btn.disabled = $false
$btn.click()
Write-Output $ie
Write-Output "doc is $doc"

PowerShell Function return value and further use of returned Variable

I don't get how the functions works in PowerShell. I tried it out a bit like C++ or C# but those languages I last tried out 7 years ago.
So as I try to work with the functions I have this function:
function whichcsv(){
$location = New-Object System.Windows.Forms.OpenFileDialog
$location.initialDirectory = $initialDirectory
$location.filter = "CSV (*.csv)| *.csv"
$location.ShowDialog()
write-host $location.FileName "in Function"
}
which determines the location of the csv that is loaded afterwards but as soon as I try to load the variable $location outside of the function it's NULL
With the write-host statement you can see it has the full path of the file.
As soon as I try to load it outside the function right after the code it won't work as its says its NULL
...
#Select which CSV
whichcsv
...
$CSV = Import-Csv -Path $location.FileName -UseCulture
$y = $CSV | Select Inventarnummer
$Filter = "Inventarnummer"
I tried to set my code in a int main(void) like in C-languages but I don't know how to handle this as well as there it would have been on the same scoope so it should have worked so but somehow it doesn't works as then I only get all in the console prompt but nothing ever happens
Full code for repro
#Importend:
#This is Work in Progress and not completed work.
Add-Type -AssemblyName System.Windows.Forms
Add-Type -AssemblyName System.Drawing
#Function Assembling
Function SaveWorkingdestination ()
{
$Saveworking = New-Object -Typename System.Windows.Forms.SaveFileDialog
$Saveworking.filter = "CSV (*.csv)| *.csv"
$Saveworking.ShowDialog()
return $Saveworking
}
function Savefaileddestination ()
{
$Savefailed = New-Object -Typename System.Windows.Forms.SaveFileDialog
$Savefailed.filter = "CSV (*.csv)| *.csv"
$Savefailed.ShowDialog()
return $Savefailed
}
function Compare ($location)
{
#work in progress
$CSV1 = Import-Csv -Path $location.FileName -UseCulture
$CSV2 = Import-Csv -Path $location.FileName -UseCulture
Compare-Object $CSV1 $CSV2 -property WhichColumn -IncludeEqual
return comparedfilename
}
function whichcsv(){
$location = New-Object System.Windows.Forms.OpenFileDialog
$location.initialDirectory = $initialDirectory
$location.filter = "CSV (*.csv)| *.csv"
$location.ShowDialog()
write-host $location.FileName "in Funktion"
}
function Checktrough ($y , $Filter,$Saveworking,$Savefailed)
{
foreach($n in $y)
{
try {
$Computer = [system.net.dns]::resolve($n.$Filter) | Select HostName,AddressList
$IP = ($Computer.AddressList).IPAddressToString
Write-Host $n.$Filter $IP
New-Object PSObject -Property #{IPAddress=$IP; Name=$n.$Filter} | Export-Csv $Saveworking.FileName -NoTypeInformation -Append
} catch {
Write-Host "$($n.$Filter) is unreachable."
New-Object PSObject -Property #{Name=$n.$Filter} | Export-Csv $Savefailed.FileName -NoTypeInformation -Append
}
}
}
#int main (void) #doesnt working so far
#{
#Select which option Form
$form = New-Object System.Windows.Forms.Form
$form.Text = "CSV Liste"
$form.Size = New-Object System.Drawing.Size(300,300)
$form.StartPosition = "CenterScreen"
$OKButton = New-Object System.Windows.Forms.Button
$OKButton.Location = New-Object System.Drawing.Point(75,195)
$OKButton.Size = New-Object System.Drawing.Size(75,23)
$OKButton.Text = "OK"
$OKButton.DialogResult = [System.Windows.Forms.DialogResult]::OK
$form.AcceptButton = $OKButton
$form.Controls.Add($OKButton)
$CancelButton = New-Object System.Windows.Forms.Button
$CancelButton.Location = New-Object System.Drawing.Point(150,195)
$CancelButton.Size = New-Object System.Drawing.Size(75,23)
$CancelButton.Text = "Cancel"
$CancelButton.DialogResult = [System.Windows.Forms.DialogResult]::Cancel
$form.CancelButton = $CancelButton
$form.Controls.Add($CancelButton)
$label = New-Object System.Windows.Forms.Label
$label.Location = New-Object System.Drawing.Point(10,20)
$label.Size = New-Object System.Drawing.Size(280,20)
$label.Text = "Welche CSV Liste soll geladen werden:"
$form.Controls.Add($label)
$listBox = New-Object System.Windows.Forms.ListBox
$listBox.Location = New-Object System.Drawing.Point(10,40)
$listBox.Size = New-Object System.Drawing.Size(260,20)
$listBox.Height = 150
[void] $listBox.Items.Add("AS400 Computer")
[void] $listBox.Items.Add("AS400 Personalstamm")
[void] $listBox.Items.Add("ADComputer")
[void] $listBox.Items.Add("ADBenutzer")
#Formclosed
$form.Controls.Add($listBox)
$form.Topmost = $True
$result = $form.ShowDialog()
if ($result -eq [System.Windows.Forms.DialogResult]::OK)
{
#Select which CSV
whichcsv
$x = $listBox.SelectedItem
switch ($x)
{
#Option 1
"AS400 Computer"
{
$CSV = Import-Csv -Path $location.FileName -UseCulture
$y = $CSV | Select Inventarnummer
$Filter = "Inventarnummer"
#SaveWorkingdestination($Saveworking)
#Export-Csv $Saveworking.FileName -NoTypeInformation -Append
}
#Option 2
"AS400 Personalstamm"
{
#not implemented yet
$y = $CSV | Select SpaltennameBzwFilter
$Filter = "Spaltennamme bzw Filter"
}
#Option 3
"ADComputer"
{
$CSV = Import-Csv -Path $location.FileName -Delimiter ','
$y = $CSV | Select Name
$Filter = "Name"
SaveWorkingdestination
Savefaileddestination
Checktrough
}
#Option 4
"ADBenutzer"
{
#not implemented yet
$y = $CSV | Select SpaltennameBzwFilter
$Filter = "Spaltenname bzw Filter"
}
}
}
#}
Maybe someone knows how to help me eather with getting the common code in something like the int main (void) from c languages or how to get a proper return from the functions... if there are still unclearitys i will clearly answer them and edit to get this working
edit: with script part it works perfectly fine so far, but now is there a format question to get some more structure in it. or is it common to have no wrap around in powershell scripts like you have in c languages with the
int main (void)
{
...
code
...
}
In your example:
function whichcsv(){
$location = New-Object System.Windows.Forms.OpenFileDialog
$location.initialDirectory = $initialDirectory
$location.filter = "CSV (*.csv)| *.csv"
$location.ShowDialog()
write-host $location.FileName "in Function"
}
$location, as assigned in the function body, is local to the function's scope. In PowerShell you can read variables from a parent scope, but writing to a variable creates a local copy by default, not persisted in the caller's scope.
What you want to do is return it's value from the scope, just like you would in a C-like language.
The caveat in PowerShell is that any value expression inside the function body that outputs anything will "bubble up" to the caller, not just the argument to return. So if you have statements inside the function body that return any value, make sure you capture or suppress that output:
function whichcsv(){
$location = New-Object System.Windows.Forms.OpenFileDialog
$location.initialDirectory = $initialDirectory
$location.filter = "CSV (*.csv)| *.csv"
[void]$location.ShowDialog() # <-- ShowDialog() returns a DialogResult, suppress it
return $location.FileName # return the filename property value
}
Then in the calling scope:
$CsvPath = whichcsv
$CsvPath will now contain the value of $location.Filename after the function returns
For more information about variable scoping in PowerShell, see the about_Scopes help topic
For more information about the behavior of return, see the about_Return help topic
For more information about the reason for this behavior in the first place, look into pipelines
You may have to use $scriptto change the scope level in which the variable can be used. To make the variable available outside the function do something like:
function whichcsv(){
$location = New-Object System.Windows.Forms.OpenFileDialog
$location.initialDirectory = $initialDirectory
$location.filter = "CSV (*.csv)| *.csv"
$location.ShowDialog()
$script:locationfilename = $location.FileName
}
write-host "$($locationfilename) in Function"
you have to return the object to the main program.
function whichcsv(){
$location = New-Object System.Windows.Forms.OpenFileDialog
$location.initialDirectory = $initialDirectory
$location.filter = "CSV (*.csv)| *.csv"
$location.ShowDialog()
return $location.FileName
}
$path= whichcsv
write-host $path

How can I make a win32 command (sqlcommand) print its output to the console in PowerShell

I have a script that eventually calls this line
& sqlcmd.exe -S $DbHost -d $DbSchema -Q "do some crazy db change here"
Where "do some crazy db change here" will eventually be replaced by a dynamic bit of SQL/script.
When I run this whether it succeeds or not I see no output from sqlcmd.exe in my console. For user feedback I'd like to pipe this in real time to the console. How could I do that?
Here's how I have done it in the past, it makes use of events from StandardOut and StandardError. As these are executed asynchronously you are not entirely in control of the output (in terms of when it happens), but it should be close to what you need.
$SqlCommandArguments = #()
$SqlCommandArguments += "-S $DbHost"
$SqlCommandArguments += "-d $DbSchema"
$SqlCommandArguments += "-Q `"do some crazy db change here`""
ExecuteProcess -FileName "SqlCmd.exe" -CommandArguments $SqlCommandArguments -Verbose:$VerbosePreference
function ExecuteProcess
{
[cmdletbinding()]
param
(
[string]$FileName,
[string[]]$CommandArguments
)
Write-Verbose "$FileName $CommandArguments"
$startInfo = New-Object System.Diagnostics.ProcessStartInfo
$startInfo.FileName = $FileName
$startInfo.Arguments = $CommandArguments
$startInfo.RedirectStandardError = $true
$startInfo.RedirectStandardOutput = $true
$startInfo.UseShellExecute = $false
$startInfo.CreateNoWindow = $true
$process = New-Object System.Diagnostics.Process
$process.StartInfo = $startInfo
$eventOutputDataReceived = Register-ObjectEvent -InputObject $process -EventName OutputDataReceived -MessageData $VerbosePreference -Action {
if ($($EventArgs.data))
{
Write-Verbose $EventArgs.data -verbose:$event.MessageData
}
}
$global:standardError = New-Object System.Text.StringBuilder
$eventErrorDataReceived = Register-ObjectEvent -InputObject $process -EventName ErrorDataReceived -Action {
if ($($EventArgs.data))
{
$global:standardError.Append("$($EventArgs.data)`r`n")
Write-Warning -message $EventArgs.data
}
}
$process.Start() | Out-Null
$process.BeginOutputReadLine()
$process.BeginErrorReadLine()
$process.WaitForExit()
Unregister-Event -SourceIdentifier $eventOutputDataReceived.Name
Unregister-Event -SourceIdentifier $eventErrorDataReceived.Name
$exitCode = $process.ExitCode
if ($exitCode -ne 0)
{
Write-Error $global:standardError.ToString()
throw "$FileName Failed!"
}
}