Function behavior changes when converted to a module resource

Welcome Forums General PowerShell Q&A Function behavior changes when converted to a module resource

This topic contains 2 replies, has 2 voices, and was last updated by

 
Participant
2 years, 11 months ago.

  • Author
    Posts
  • #33460

    Participant
    Points: 0
    Rank: Member

    This may be a security thing, but basically I have some functions that I originally kept in a file.ps1, and would simply "import-module file.ps1", use the functions, then move on with my life.

    I've sense decided to turn them into a more formal module by converting it into a file.schema.psm1 and accompanying file.psd1 manifest. LItterally little more than a rename and adding a manifest.

    But one of my functions no longer works after this change. It' a function that does something a little less conventional: it reads an xml file of username and passwords and then converts them all to credentials. This way I can quickly "import" an xml file of username/passwords to be called by whatever other random scripts I want to run ... less typing ... yippie.

    Now that it's a more "formal module" the function "appears" to work ... but after running I have no variables in memory to be called. Sample snippet here:

    Function New-PasswordScriptVariable
    {
    param(
        [Parameter(Mandatory=$True)][String]$Name,
        [Parameter(Mandatory=$True)][String]$User,
        [Parameter(Mandatory=$True)][String]$Password
        )
    
        $SecurePass = ConvertTo-SecureString $Password -AsPlainText -Force
        Invoke-Expression ("`$$Name = New-Object System.Management.Automation.PSCredential $User, `$SecurePass")
    }
    

    So run this in a prompt or save as a ps1, import, and run it and you can do something easily like "new-passwordScriptVariable -name sample -user "contoso\jdoe" -password "blah"

    then notice you have $sample ready to go. However ... package it away as a module ... nothing happens (or maybe sometime happens but I never see the variable in my user context).

    Tips?

  • #33461

    Member
    Points: 0
    Rank: Member

    There's very little value in having your function be responsible for creating the variable. You can just return the credential object, and have the calling code assign it to a variable if it wants to. For example:

    Function New-PasswordScriptVariable
    {
    param(
        [Parameter(Mandatory=$True)][String]$User,
        [Parameter(Mandatory=$True)][String]$Password
        )
    
        $SecurePass = ConvertTo-SecureString $Password -AsPlainText -Force
        New-Object System.Management.Automation.PSCredential $User, $SecurePass
    }
    
    # calling code
    
    $cred = New-Credential -User Bob -Password Whatever
    

    If you really want your function to set a variable out in the scope of the calling function (and a module is involved), you need to use the $PSCmdlet variable.

    Incidentally, Invoke-Expression is very dangerous if you're working with input that is not completely safe / trusted. This example will avoid that, since it's not needed anyway:

    Function New-PasswordScriptVariable
    {
    param(
        [Parameter(Mandatory=$True)][String]$Name,
        [Parameter(Mandatory=$True)][String]$User,
        [Parameter(Mandatory=$True)][String]$Password
        )
    
        $SecurePass = ConvertTo-SecureString $Password -AsPlainText -Force
        $cred = New-Object System.Management.Automation.PSCredential $User, $SecurePass
        
        $PSCmdlet.SessionState.PSVariable.Set($Name, $cred)
    }
    
    
  • #33463

    Participant
    Points: 0
    Rank: Member

    I appreciate the help, perhaps my "poor man's password vault" is just a bad idea.

    Essentially your first example doesn't spit out a "variable variable". it spits out credentials to a fixed name variable. That's not what I'm trying to accomplish, as I'm hoping to be able to create multiple variables so that I can do things like essentially dump some common credentials out then call them ass needed for different things.

    install-sql.ps1 -creds $SQLSVC
    install-DC.ps1 -creds $DomainAdmin

    Basically I pull them up in one line ... run all my various credential required cmdlets ... close the session when I'm done. It's a convenience thing.

    Your second example may be better if I"m planning to run this function from within another script ... if I understand what it's doing ... but I'm not certain I do ... but Ill give it a go and see what happens 🙂

    Edit: looks like I got it working (thank you!)

    Your second example was key ... with one missing piece being I needed [cmdletbinding()] defined .... got that info from your blog 🙂

The topic ‘Function behavior changes when converted to a module resource’ is closed to new replies.