April 8, 2016 at 1:11 pm #37452
I'm writing a module to use the Force.com API. I have two core functions:
- New-ForceSession – returns a session ID and servicing server URL
- Invoke-ForceRest – this is what actually is calling (Invoke-RESTMethod) to Force.com. This is the function that needs the session information
The remaining functions are Get and Set functions that basically build a URL and JSON parameters and call the Invoke-ForceRest. The current way I have written it is you create a session and then pass the session to each respective Get and Set with a session parameter.
$session = New-ForceSession -User email@example.com -Password "blu3b!rd" Get-Something -Session $session
Everything works great. I just don't like having to pass the session information from my Get-Something that calls Invoke-ForceRest which actually needs the session information. If I call New-ForceSession in Invoke-ForceREST, I need to get it the username, password, etc. and I'll be calling it over and over again for each respective Get\Set call I make.
Is there a better way to store the session information globally in the module versus passing it every time? If I set global variables in New-ForceSession (e.g. $script:SessionID = $myVar.SessionID), is that the best way to do it? I'm just trying to figure out the cleanest way to do something like this:
New-ForceSession -User firstname.lastname@example.org -Password "blu3b!rd" Get-Something | Set-Something
Just looking for best practice recommendations. As I said, the current code works great, it just drives me a little crazy that I have to pass the same thing over and over.
April 8, 2016 at 1:30 pm #37454
Well, you don't want it globally per se, you want it module-lar-ly.
What I typically do is establish and export a module-level preference variable, like $DonErrorLogPath (the "Don" namespaces it to avoid overlap). I set that to some default value.
Then, all my functions expose an -ErrorLogPath parameter which is non-mandatory, and which defaults to $DonErrorLogPath.
So you could do something similar. Set up a $RobForceSession module-level variable, and make sure it gets exported, so it'll end up in the global scope _while the module is loaded_. Your other functions can then have a -ForceSession parameter that defaults to $RobForceSession. Obviously, you'd have to make sure you set $RobForceSession at the top of a script:
$RobForceSession = New-ForceSession blah blah blah
Note that none of your functions are internally setting that variable – it's either being set as the output of New-ForceSession, or passed into a function as a parameter. That maintains a nice "wall" around each function. It also means that for a one-off, you could do:
Get-Something -ForceSession (New-ForceSession blah blah blah)
Which is a native pattern PowerShell tends to use a lot.
Now... this still requires Get-Something to internally pass the session object to Invoke-ForceRest. But that's the "right" way to do it. I suppose the only other way would be to omit a -ForceSession parameter from Get-Something, and just call Invoke-ForceRest with $RobForceSession. But that's a little... invisible for me. It becomes less clear where data is coming from, and the priority should be making things clear for the USER, not the programmer.
April 8, 2016 at 8:04 pm #37460
The (demo-ish) Infoblox module here shows a common pattern you might consider:
- Keep a serialized (pick your poison) copy of data that can be serialized.
- Initialize that file, or read it in on module load. Just a normal variable. This will be available to other functions in the module.
- Ideally, write Get- and Set-SomeConfig functions to retrieve or write this information, respectively. Consider whether you want to update both the live variable and serialized copy in one shot.
- Use the live variable as a default parameter value as desired
See the Infoblox.psm1 file, Get-IBConfig.ps1, and Set-IBConfig.ps1 files for examples.
Certainly not the only way, or right way to do it, but I've found it convenient to use, and reasonably straightforward to write. Very similar to Don's, I just like to serialize what I can to save typing : )
April 11, 2016 at 7:05 am #37509
Thanks for the assistance. Reviewing the code that Warren posted, it appears to store the session information as a cookie (#RamblingCookieMonster) and then in leveraged as a global variable in the code. I also liked the idea of using -PassThru to store it as a variable as an option to maintain the way it's currently passing the data manually as a session.
One thing that is annoying is that Force.com doesn't seem to actually provide in it's response is a timeout date\time. Basically, I'd need to add logic in the catch if there is a unauthorized message to refer to New-ForceSession.
Overall, I really like your approach in the InfoBlox code. It made me rethink a couple of things like maintaining a couple thousand lines of code in the PSM1 versus creating files and dot sourcing them. Thank you for sharing and the guidance.
You must be logged in to reply to this topic.