ecitsolutions / Autotask

A PowerShell module for Autotask Web Services API
MIT License
65 stars 18 forks source link

Variables do not seem to pass from parameters into Filter scope. #82

Closed ArtisanByteCrafter closed 3 years ago

ArtisanByteCrafter commented 4 years ago

I'm using version 1.6.6 for this issue.

If I specify this, it works perfect:

$StartDate = [datetime]'5/2/2020'
$EndDate = [datetime]::today
$billingItems = Get-AtwsBillingItem -Filter {PostedDate -ge $StartDate -and PostedDate -le $EndDate}

However, by simply encapsulating the same code into a function and attempting to pass the values in as parameters, I receive an error:

Function Test-Billing {
    param(
        $StartDate,
        $EndDate
    )
    $billingItems = Get-AtwsBillingItem -Filter {PostedDate -ge $StartDate -and PostedDate -le $EndDate}
    $billingitems.count
}
Test-Billing -StartDate ([datetime]'5/2/2020') -EndDate ([datetime]::today)

Error received:

Update-AtwsFilter : Update-AtwsFilter: Could not find any variable called $StartDate. Is it misspelled or has it not
been set yet?
At C:\Users\<username>\Documents\WindowsPowerShell\Modules\Autotask\1.6.6\Dynamic\Get-AtwsBillingItem.ps1:575 char:23
+             $Filter = . Update-AtwsFilter -Filterstring $Filter
+                       ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
    + CategoryInfo          : NotSpecified: (:) [Write-Error], WriteErrorException
    + FullyQualifiedErrorId : Microsoft.PowerShell.Commands.WriteErrorException,Update-AtwsFilter

I believe this might be scope related, as I can get around it this way:

Function Test-Billing {
    param(
        $StartDate,
        $EndDate
    )
    $Global:start = $StartDate
    $Global:End = $EndDate
    $billingItems = Get-AtwsBillingItem -Filter {PostedDate -ge $Global:Start -and PostedDate -le $Global:End}
    $billingitems.count
}

Test-Billing -StartDate ([datetime]'5/2/2020') -EndDate ([datetime]::today)

I'd really like to avoid global variables if at all possible, but i wanted to bring it up as how i managed to work around it.

Thanks again for all your hard work on this module!

klemmestad commented 4 years ago

Thank you @ArtisanByteCrafter, you are spot on! The issue is scope related. When a module function get to the part where it tries to access the Filter variables there are just no way (that I have found) to access any local variables from a function, just like you demonstrate.

You use global: in your example, does that mean that script scope failed? I, too, dislike using Global variables, so it would have been nice to figure out a different way of doing it. But global variables does work, just like you demonstrate.

bjowol commented 3 years ago

Thank you @ArtisanByteCrafter, you are spot on! The issue is scope related. When a module function get to the part where it tries to access the Filter variables there are just no way (that I have found) to access any local variables from a function, just like you demonstrate.

You use global: in your example, does that mean that script scope failed? I, too, dislike using Global variables, so it would have been nice to figure out a different way of doing it. But global variables does work, just like you demonstrate.

SeeminglyScience commented 2 years ago

When a module function get to the part where it tries to access the Filter variables there are just no way (that I have found) to access any local variables from a function, just like you demonstrate.

$PSCmdlet.SessionState will contain the session state of the caller. So for your Update-Filter command you would need to do something like this:

function Test-PublicFacingCommand {
    [CmdletBinding()]
    param([string] $VariableName)
    end {
        $value = GetCallerVariableValue -Context $PSCmdlet -VariableName $VariableName
    }
}

function GetCallerVariableValue {
    [CmdletBinding()]
    param(
        [System.Management.Automation.PSCmdlet] $Context,
        [string] $VariableName
    )
    end {
        return $Context.SessionState.PSVariable.GetValue($VariableName)
    }
}