none
General variables, store them in a psm1? RRS feed

  • Question

  • Quick question, looking for best approach.
    I'd like to store some general variables, f.e. $GroupHelpdesk, $RDSBroker, $NamofOurOrganization, $MyName etc so I can easily use/refer to them in all my scripts and easily handover my scripts to other people telling they only need to change these variables. That's the right way to go, right (powershell module MyVariables.psm1)?

    Please advise.
    J.


    Jan Hoedt

    Friday, August 19, 2016 2:45 PM

Answers

  • Hi Jan,

    I'd advice against configuration management in a module-scriptfile hardcoded.

    Consider the following avenues:

    • Autodetection features:
      Some settings can actually be deduced by the environment. Automatically finding the RDS Broker should not be impossible. You can help autodetection along with DNS entries, Service Connection Points, etc.
    • Configuration module:
      Create a module that is designed to manage configurations. That is, the actual configuration file is an XML stored (for example) in AppData. The module publishes some functions such as Set-Config and Get-Config. That way you can tell users to just run these.
    • Parameterization:
      Some information might as well be required to pass by parameter. This is especially true for often changing values.

    If you force them to edit the script files, this means that your modules will only ever work, if your users have write access to code that is executed. Given the current rate of threat escalation that is a horrible security design. Even if your users are currently able to do this, you may later want to change this and you'd have to rewrite every piece of code ...

    Cheers,
    Fred


    There's no place like 127.0.0.1

    Friday, August 19, 2016 3:10 PM

All replies

  • Why do you need that, when you can prompt for parameters?

    -- Bill Stewart [Bill_Stewart]

    Friday, August 19, 2016 2:52 PM
    Moderator
  • Hi Jan,

    I'd advice against configuration management in a module-scriptfile hardcoded.

    Consider the following avenues:

    • Autodetection features:
      Some settings can actually be deduced by the environment. Automatically finding the RDS Broker should not be impossible. You can help autodetection along with DNS entries, Service Connection Points, etc.
    • Configuration module:
      Create a module that is designed to manage configurations. That is, the actual configuration file is an XML stored (for example) in AppData. The module publishes some functions such as Set-Config and Get-Config. That way you can tell users to just run these.
    • Parameterization:
      Some information might as well be required to pass by parameter. This is especially true for often changing values.

    If you force them to edit the script files, this means that your modules will only ever work, if your users have write access to code that is executed. Given the current rate of threat escalation that is a horrible security design. Even if your users are currently able to do this, you may later want to change this and you'd have to rewrite every piece of code ...

    Cheers,
    Fred


    There's no place like 127.0.0.1

    Friday, August 19, 2016 3:10 PM
  • So this is what I came up with

    $ScriptPath = (Split-Path ((Get-Variable MyInvocation).Value).MyCommand.Path)
    $GlobalVariables = $ScriptPath + "\GlobalVariables.ps1"
    Get-Content $GlobalVariables


    Jan Hoedt

    Thursday, November 10, 2016 12:36 PM
  • Hi Jan,

    that may work, but it will cause you pain. Well, it will work, if you import it in the last line, rather than get-content it:

    $ScriptPath = $MyInvocation.MyCommand.Path
    $GlobalVariables = $ScriptPath + "\GlobalVariables.ps1"
    . $GlobalVariables

    It will however cause some flexibility issues and headaches along the way (for example the good old "What version of script and config is this?" issue, where you need to manually check each time whether the thing is set up correctly.

    A somewhat less volatile solution might be this, if you are within a single domain:

    . "\\dfs\root\Scripts\profiles\global.ps1"
    . "\\dfs\root\Scripts\profiles\$($env:Username).ps1"

    This allows setting up a global profile and a user specific profile, allowing users to override any of your default variables.

    Cheers,
    Fred

    P.s.: I know I may be a pain in the ass, but once again I recommend choosing a non-scripted way to retrieve / provide as much of these pieces of information as possible. The disadvantages are just too many.


    There's no place like 127.0.0.1



    • Edited by FWN Thursday, November 10, 2016 2:32 PM
    Thursday, November 10, 2016 12:49 PM
  • Thanks but can't make that work. Could be because I'm using ISE?


    Jan Hoedt

    Thursday, November 10, 2016 2:01 PM
  • Can't make this work either


      & ((Split-Path $MyInvocation.InvocationName) + "\GlobalVariables.ps1")


    Jan Hoedt

    Thursday, November 10, 2016 2:21 PM
  • Thanks but can't make that work. Could be because I'm using ISE?


    Jan Hoedt

    Actually, sorry, but I had a typo in my snippet.

    There's no place like 127.0.0.1

    Thursday, November 10, 2016 2:33 PM
  • MyScriptPath is empty, $MyInvocation is empty when I run in debug

    Jan Hoedt

    Thursday, November 10, 2016 4:42 PM
  • Hi Jan,

    automatic variables such as $MyInvocation will change as you switch scope-sources. Odds are, whatever debugger you use has this effect. Try putting this into a scriptfile and run it:

    $MyInv = $MyInvocation
    $host.EnternestedPrompt()

    You enter a nested prompt, where $MyInvocation will be mostly empty. However the script's own invocation info was stored in $MyInv - check out its contents.

    Cheers,
    Fred


    There's no place like 127.0.0.1

    Friday, November 11, 2016 8:32 AM
  • I'm not sure I fully understand what you mean.
    I'm just using Powershell ISE as an editor. However, I ran what you mentioned and had this result:

    MyCommand             : test.ps1
    BoundParameters       : {}
    UnboundArguments      : {}
    ScriptLineNumber      : 0
    OffsetInLine          : 0
    HistoryId             : 3668
    ScriptName            : 
    Line                  : 
    PositionMessage       : 
    PSScriptRoot          : 
    PSCommandPath         : 
    InvocationName        : E:\MyScripts\TestScript\test.ps1
    PipelineLength        : 3

    So it does show invocationname. What I should conclude it not really clear.

    This  approach (currently) works for me though:

    $ScriptPath = (Split-Path ((Get-Variable MyInvocation).Value).MyCommand.Path)
    $GlobalVariables = $ScriptPath + "\GlobalVariables.ps1"
    . $GlobalVariables

    Your explanation on it "some flexibility issues and headaches along the way (for example the good old "What version of script and config is this?" issue, where you need to manually check each time whether the thing is set up correctly."

    I don't see it right now. Since that's the only thing which is working for me now, I'd better follow this approach and adapt to yours when it is clear to me.
    Note that I won't use the  DFS-option. It rings a bell, but I'm not that far yet and just want to make my script work for now, then think bigger (dfs) later :-)


    Jan Hoedt

    Monday, November 14, 2016 1:08 PM