This one took my some time to complete. Much more than I thought it will. But I gotta say, I'm rather proud of this one.
The problems I wanted to solve was setting up the
$PROFILEfile needs to do some work to support the environment I've created.
- I want to have only the Scripts directory in the git repo, which means the
$PROFILEfile will not be pulled when I clone the repo.
- With the above stated, this means setting up my environment requires multiple steps:
- If the
Scriptsdir doesn't exists create it.
- git clone the repo into the
- Create the
$PROFILEfile and paste in the code*.
- If the
- * Currently, The relevant
$PROFILEcode is in the git repo's README.md
- Editing the
$PROFILEfile isn't synced into the git repo.
$PROFILEcan be in one of two contexts, CurrentUser or AllUsers (this isn't even counting the different CurrentHost and AllHosts contexts), making syncing even more troublesome.
- Even if
$PROFILEwould be pulled from the git repo, doing it blindly can be bad, as there might be a need for some unique system/user specific code.
Coming up with a plan
I wanted to come up with a solution that would simplify the entire setup process and solve the problems listed above.
I was determined to create a
Setup-Profile script that will address those problems, it would have the following goals:
- The script file will contain the code for the
$PROFILEfile. This way, the code is saved and managed in git. From this point forward, this code will be named common-profile-code
- Ability to remove/refresh the common-profile-code easily. If there is code before or after the common code, only affect the common code block.
- Ability to work in either contexts (CurrentUser or AllUsers).
Seems simple enough.
Wait, there's more...
While starting to code, I got most of this done, mostly based on some older code I wrote, and then I thought of one more concept.
I got the notion to transform the script so it would allow an easy setup of the
Scripts dir environment. The idea is to be able to pull its code using
Invoke-WebRequest and feeding it into
Invoke-Expression. This will allow me to construct a one-liner setup call (like the one at the top of this post), that will do all the setup needed to get the environment up and running.
This threw me into a spin, because this introduced one more complications:
- The script must be totally self-sufficient, and cannot assume anything about the environment.
The reason this is so important is because the script I already came up with already relied on a few of the function-scripts I've created.
A Lesson Learned
This is probably a great lesson to pause and contemplate upon:
It's important to form a philosophy to guide you, but it's even more important to identify when the rules set by will not serve you and exceptions will need to be made.
Setup-Profile script is going to change some things around.
It is going to contain some functions that will be loaded into memory and not stored in the
Scripts dir like I intended originally.
One important philosophy I do want to stick to, is:
Whenever possible, do not duplicate reusable code.
I'll start by laying out the different components of the script:
ProfileCode_commonfunction: Shared code between the
Setup-Profilescript code and the actual
$PROFILE. The code is completely self-sufficient and includes several common functions that will become an integral part of the run-time environment.
ProfileCode_post_commonfunctions: Each containing code that should be written into the common-profile-code but not necessarily run in-line whlie the script runs.
Setup-Profilescript, containing the above mentioned functions, and used to setup the $PROFIEL as well as it's supporting environment. The script has the following features:
- Can run without any dependency on any other script
- Decides on the prefered
$PROFILEcontext based on the following:
- If running as admin, chooses the AllUsers context, otherwise write to CurrentUser context.
- If passed the
-sudoswitch, will use
sudoto acheive 'running as admin' status, will use
sudoonly on global resources.
- If code exists, will replace it, otherwise will insert the code at the beginning of the
- Can be run with
-RemoveOnlyto only remove existing common-profile-code.
- Respect existing content, and ask permission before destroying exsiting work.
The following are functions embedded within
ProfileCode_common. These will always be part of the loaded profile:
- 'Get-PowerShellPath' - Identifies the path of the shell
- 'Export-FunctionSource' - Exports the source code of functions, either with the function name header, or without.
- `Test-IsAdmin' - return $True when running 'as admin'
- 'ConvertTo-Base64' - outputs a Base64 version of it's input string
- 'Invoke-ExpressionEx' - An extention for Invoke-Expression, one that will allow runing PowerShell code, even functions, with sudo (or without).
How to Use the
The script syntax is as follows:
Probably, the most common invocation, in an environment already setup, where you would like to update existing
$PROFILE would be:
Setup-Profile [-sudo] -Force
-Force will be required here to overwrite an already existing
Where this script really shines though, is in it's direct-from-web invocation:
Invoke-WebRequest https://code.lksz.me/lksz/PowerShell_Scripts/raw/Setup-Profile.ps1 | Invoke-Expression
or the shorthand version (also the first line of this post)
iwr https://lksz.me/pwsz | iex
This will grab the code from the
https://code.lksz.me/lksz/PowerShell_Scripts/raw/Setup-Profile.ps1 URL, pass it through
One final trick this script does, is loading the entire script into memory, allowing to construct a one-liner that not only loads the script from the web it also allows to execute it with parameters:
* Source Code
|Link to latest version||At the time of writing|