spassen
spassen

Reputation: 1580

Adding PowerShell functions to an object

I have a PowerShell module with a group of functions.

The function createService creates an instance of a service and returns a variable. Several of my functions use the returned value, but I only want one instance of the service so I cannot call createService in each function.

On the command line, I can do $var = createService($string), then call update($var) and it will work properly, but I don't want to force the user to remember to use $var as a parameter.

Is there a way to put these functions in an object/class so the variable can be stored globally and referenced inside each function instead of through parameters?

Upvotes: 1

Views: 316

Answers (2)

Rynant
Rynant

Reputation: 24343

In your module, if you assign the service object to a script scoped variable, all functions in the module can access the variable. Here is an example:

$module = {
    function StartNewService {
        $script:service = 'MyService'
    }
    function UpdateService {
        "Updating service: " + $script:service
    }
    Export-ModuleMember -Function StartNewService, UpdateService
}

$null = New-Module $module

# StartNewService creates the service variable.
StartNewService
# UpdateService accesses the service variable created by StartNewService.
UpdateService

If you declare the variable as $global:service, you can access the variable from outside the module as well.

Edit: To address the comments below, here is a more practical example that shows an appropriate situation for sharing a variable among functions in a module. In this case all of the functions in the module depend on the same instance of the $Locations variable. In this example the variable is created outside of the functions, and is kept private by not including it in the Export-ModuleMember command.

Here is a simplified version of my LocationName.psm1

$Locations = @{}

function Save-LocationName {
    param(
        [parameter(Mandatory=$true)]
        [string]$Name
    )
    $Locations[$Name] = $PWD
}

function Move-LocationName {
    param(
        [parameter(Mandatory=$true)]
        [string]$Name
    )
    if($Locations[$Name]) {
        Set-Location $Locations[$Name]
    }
    else {
        throw ("Location $Name does not exist.")
    }
}

New-Alias -Name svln -Value Save-LocationName
New-Alias -Name mvln -Value Move-LocationName

Export-ModuleMember -Function Save-LocationName, Move-LocationName -Alias svln, mvln

With this module a user can give a name to a directory, and move to that location by using the given name. For example if I am at \\server01\c$\Program Files\Publisher\Application\Logs, I can save the location by entering svln logs1. Now if I change my location, I can return to the logs directory with mvln logs1. In this example it would be impractical to use the locations hashtable for input and output since the functions are always working with the same instance.

Upvotes: 0

Roman Kuzmin
Roman Kuzmin

Reputation: 42073

I would propose to start the service by the exposed functions, so that a user does even have to care of starting it.

$module = {
    # The only service instance, $null so far
    $script:service = $null

    # Starts the service once and keeps its the only instance
    function Start-MyService {
        if ($null -eq $script:service) {
            "Starting service"
            $script:service = 'MyService'
        }
    }

    # Ensures the service by Start-MyService and then operates on $script:service
    function Update-MyService1 {
        Start-MyService
        "Updating service 1: $script:service"
    }

    # Ensures the service by Start-MyService and then operates on $script:service
    function Update-MyService2 {
        Start-MyService
        "Updating service 2: $script:service"
    }

    Export-ModuleMember -Function Update-MyService1, Update-MyService2
}

$null = New-Module $module

# Starting service
# Updating service 1: MyService
Update-MyService1

# Updating service 2: MyService
Update-MyService2

Upvotes: 1

Related Questions