iwr https://lksz.me/pwsz | iex
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 Problem
The problems I wanted to solve was setting up the $PROFILE
file:
- The
$PROFILE
file 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
$PROFILE
file will not be pulled when I clone the repo. - With the above stated, this means setting up my environment requires multiple steps:
- If the
Scripts
dir doesn't exists create it. - git clone the repo into the
Scripts
dir. - Create the
$PROFILE
file and paste in the code*.
- If the
- * Currently, The relevant
$PROFILE
code is in the git repo's README.md - Editing the
$PROFILE
file isn't synced into the git repo. $PROFILE
can 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
$PROFILE
would 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
$PROFILE
file. 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.
This 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.
The Details
I'll start by laying out the different components of the script:
ProfileCode_common
function: Shared code between theSetup-Profile
script 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_pre_common
andProfileCode_post_common
functions: Each containing code that should be written into the common-profile-code but not necessarily run in-line whlie the script runs.Setup-Profile
script, 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
$PROFILE
context based on the following:- If running as admin, chooses the AllUsers context, otherwise write to CurrentUser context.
- If passed the
-sudo
switch, will usesudo
to acheive 'running as admin' status, will usesudo
only on global resources. - If code exists, will replace it, otherwise will insert the code at the beginning of the
$PROFILE
file. - Can be run with
-RemoveOnly
to 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 Setup-Profile
Script
The script syntax is as follows:
Setup-Profile [-sudo] [-RemoveOnly] [-GitClone [-GitURL <string>]] [-Force] [-ShowSkipped] [-WhatIf] [-Confirm] [<CommonParameters>]
Probably, the most common invocation, in an environment already setup, where you would like to update existing $PROFILE
would be:
Setup-Profile [-sudo] -Force
The -Force
will be required here to overwrite an already existing $PROFILE
file.
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 Invoke-Expression
.
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:
$SetupFromWeb=1; iwr https://lksz.me/pwsz | iex; _setup -sudo -GitClone
$PROFILE
to utilize it* Source Code
Link to latest version | At the time of writing |
---|---|
Edit-MyProfiles | commit ae07e06c27 |
Edit-MyScript | commit ae07e06c27 |
Edit-TextFile | commit ae07e06c27 |
Setup-Profile | commit ae07e06c27 |