Module scoping problem

Tagged: 

This topic contains 2 replies, has 2 voices, and was last updated by Profile photo of David Jones David Jones 7 months, 2 weeks ago.

Viewing 3 posts - 1 through 3 (of 3 total)
  • Author
    Posts
  • #35216
    Profile photo of David Jones
    David Jones
    Participant

    This function works when used as a helper function inside a module or when dot sourced into the current session. But does not work when exported from a module

    `
    function Mount-VhdAndRunBlock
    {

    param
    (
    # Path to VHD(x) file
    [Parameter(Mandatory=$true)]
    [ValidateNotNull()]
    [ValidateNotNullOrEmpty()]
    [string]
    $vhd,

    # Script block to execute (Drive letter stored in $driveletter)
    [Parameter(Mandatory=$true)]
    [scriptblock]
    $block,

    # Mount the VHD(x) readonly, This is faster. Use when only reading files.
    [switch]
    $ReadOnly
    )

    # This function mounts a VHD, runs a script block and unmounts the VHD.
    # Drive letter of the mounted VHD is stored in $driveLetter – can be used by script blocks
    if($ReadOnly)
    {
    $virtualDisk = Mount-VHD $vhd -ReadOnly -Passthru
    }
    else
    {
    $virtualDisk = Mount-VHD $vhd -Passthru
    }
    # Workarround for new drive letters in script modules
    $null = Get-PSDrive
    $driveLetter = ($virtualDisk |
    Get-Disk |
    Get-Partition |
    Get-Volume).DriveLetter
    & $block

    Dismount-VHD $vhd

    # Wait 2 seconds for activity to clean up
    Start-Sleep -Seconds 2
    }
    `

    `
    Mount-VhdAndRunBlock -vhd $ImagePath -block { $driveLetter } -ReadOnly
    `

    This should return the drive letter of the vhd's mount point. but I get nothing.

    I think this is a scoping issue but I'm lost on how to fix.

    #35223
    Profile photo of Dave Wyatt
    Dave Wyatt
    Moderator

    Script blocks are a bit funny; they stay bound to the caller's scope even when they're passed in to a module function as a parameter. Since you're defining $driveLetter in your module function, and the script block parameter is still bound to the caller, it can't resolve the $driveLetter variable.

    This design can be a bit of a code smell; depends on what it is you're trying to do with that script block. However, you can create a copy of the script block that isn't bound to any particular scope like this, and invoke that instead:

    $newScriptBlock = [scriptblock]::Create($block.ToString())
    & $newScriptBlock
    
    #35224
    Profile photo of David Jones
    David Jones
    Participant

    Thanks that worked perfectly. I figured you would know

    Where can I find some good references for how scoping works?

Viewing 3 posts - 1 through 3 (of 3 total)

You must be logged in to reply to this topic.