PowerShell Function return value and further use of returned Variable

12,105

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

Share:
12,105

Related videos on Youtube

Kevin
Author by

Kevin

Updated on June 04, 2022

Comments

  • Kevin
    Kevin almost 2 years

    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
        ...
    }
    
  • Kevin
    Kevin over 6 years
    ok this works out thank you, can i shorten the $script:locationfilename = $location.filename to something like $script:Fnp = $location.filename ?
  • Kevin
    Kevin over 6 years
    yeah its kinda confusing with those scopes in powershell when you first dont know about it and try to handle it like in c languages and so on... is there a ease and short explantion of those scopes from powershell? and if not to much for a question is there a wrap up like in c languages with the int main (void){}
  • Mathias R. Jessen
    Mathias R. Jessen over 6 years
    @Kevin Yeah, jumping into a fundamentally different programming environment with a similar syntax can be quite confusing :-) Look at the example in my code (the second block) - [void](statement or expression in here) is an easy way to suppress output. For scopes, have a look at the documentation
  • ShanayL
    ShanayL over 6 years
    Yeah that works too... you can use anything you like you pretty much throwing scriptat the front of your variable.
  • Kevin
    Kevin over 6 years
    allright its quite a lot of info to get into it but its a nice docu and i will work with it till i got the clue completly still one structre question open if there is a wrap up in scripting like in the c language or does the code "hang free", if i'm not wrong this would make a scope shift right? so now the free code is in local or whatever and then it would be in the "same scope" like the functions or am i wrong here?
  • Mathias R. Jessen
    Mathias R. Jessen over 6 years
    No, it won't "shift scopes", it'll only swallow output