How can I set up a default powershell profile for all my co workers at work as simple as possible? - powershell

What do I want to achieve?
I have one ps1 file that has all of my functions inside. In the first step I want to convert it into a ps module. Then I want to have the following:
Colleague gets a script or bat he has to run ONCE. This will set his Modules Environment path $Env:PSModulePath to a path on a network drive everyone has access to
Copy and paste a custom profile.ps1 into the users %userprofile%\Documents\WindowsPowershell that imports the module
Every user should now have the powershell scripts I made available in their shell
How I tried to solve it
The way me and a colleague have set it up in the past is with this:
(we have a profile.ps1 file that does the following):
#set path for profile_loader.ps1
$path = "\\server\share\folderwithscripts";
#call profile_loader.ps1
. "$path"
Then this profile_loader.ps1 baiscally just loads tons of scripts (ps1 files) like this:
. "\\server\share\pathtoanotherscript.ps1
Line after line.
I don't like it and it is too complicated for my 25 other colleagues I want to set up in the future.
Question
What is the best way to achieve this? A good old .bat file that copy and past the ps1 file into their userprofile? Or is there a better way?

As someone who had their $profile wiped and set to a "company default", for the love of god, don't.
If you have to, then I suggest just creating a profile you want everyone to have with all your modules in a shared location, like your securely locked down Sysadmin folder.
Do psedit $proile.AllUsersAllHosts on your machine, modify that, then make a text file with all the hostnames you want to destroy with your own forced profile. Throw this in there to make it import your modules by default.
# Checks your server share for any PSM1 files, could change to include PS1 as well I suppose. Long name because its in a $Profile so ¯\_(ツ)_/¯
$ModulePathWithLongNameBecauseSomeoneMayUseThisInAnActualScript = Get-ChildItem -file -Recurse "\\server\share\" -Include "*.psm1"
# Sets module path for other adhoc module calls if they dont want to restart their Powershell
$env:PSModulePath = $env:PSModulePath + ";\\server\share\"
# Imports all PSM1 files from the ModulePath*
Foreach($psm in $ModulePathWithLongNameBecauseSomeoneMayUseThisInAnActualScript){
Import-Module "$($ModulePath.FullName)"
}
Run this on your machine to deliver your soul crushing $profile to your colleagues who may have had their own setup.
# Get a list of machines that your staff will use and throw them into a txt or csv etc.
$PCsForForcedProfile = Get-Content "\\server\share\PleaseNo.txt"
Foreach($Colleague in $PCsForForcedProfile){
Copy-Item "C:\Windows\System32\WindowsPowerShell\v1.0\profile.ps1" "\\$Colleague\C$\Windows\System32\WindowsPowerShell\v1.0\" -force
}

Related

Write to Profile File After Installing PowerShell Module with PowerShellGet

I have a custom PowerShell module with two cmdlets. I have it successfully, but manually, deployed on my machine. However, I deployed it by placing the binary file and module manifest in a location, and then registering the module. I also had to manually write an Import-Module command into my 'all users' profile.
Now I am sure I can deploy this module with Publish-Module, but how do I get the Install-Module to write the Import-Module statement to the profile file?
As of PowerShell 3.0, a module is automatically imported when a command from the module is invoked. This was a brilliant on Microsoft's part; however, it did require that modules are located in a location where PowerShell looks for modules by default. Makes sense. You can see those locations by running the following command:
$env:PSModulePath -split ';'
Is there a reason you'd rather not use one of the paths stored in the above environmental variable? That said, I'd keep your code out of the "C:\Windows\System32..." path. The other options are better: "C:\Program Files\PowerShell\Modules" (AllUsers) and "C:\Users\tommymaynard\Documents\PowerShell\Modules" (CurrentUser). Depending on your PowerShell version/OS, those path could be different. You won't need to write an Import-Module command into a $PROFILE script if you get the module into a preferred location. Maybe you already know this, but maybe not.
You're not going to get Install-Module to write to any of the $PROFILE scripts.
$PROFILE | Select-Object -Property *
Well, not by default anyway. You could write your own Install-Module function, that runs PowerShellGet's Install-Module function, and includes writing to various $PROFILE scripts. The problem is that you'll need to include logic so you don't blow away the contents of someone's $PROFILE script if it's not empty, and only append to it.
Seriously though, this is turning into a lot of work, when you could drop the module into a location where PowerShell can find it on its own.
Edit: It just occurred to me, you can add a value/path to the $env:PSModulePath environmental variable. It's a single string with semi-colon delimiters:
$env:PSModulePath.GetType().Name
Therefore, it'd look like this:
$env:PSModulePath += ';C:\Another\Path'
That's great and all, but again how might you stage this, right? It takes you back to the write-to-all-the-$PROFILE-scripts problem,... although you may be able to update the variable via Group Policy Preferences. Again, probably better to just relocate your module.

How can you run a powershell script if you do not know the location is will be run from?

I am new to powershell so this may just be me not understanding something.
I am writing a tool in powershell and have the tool working in c:\Users\Documents\WindowsPowerShell\Modules.
What I would like is the ability to copy the tool to a USB stick and run it from the USB stick.
How can I get the tool to run if its not in the PSModulePath environment variable path?
Or how can I add the USB stick added to the PSModulePath path?
Thanks for the help.
I have a solution that works by placing the following in a .ps1 script and using that to import the dependent modules and call the first function.
#find local directory
$LocalDir = Split-Path $MyInvocation.MyCommand.Path -Parent
#prove correct directory found.
Write-Host "Starting module load: $($MyInvocation.MyCommand) in directory = $LocalDir"
#load modules
Import-Module $LocalDir/Module –Force
#call first function
firstfunction
I could not get $PSScriptRoot to work but the Split-Path $MyInvocation.MyCommand.Path –Parent code has the advantage in that it also works in ISE.
I then placed the dependent modules in directories below the .ps1 script.
If you want your script to be portable, you will have to carry around the dependent module with you as well. However, in your script, you can make sure to add the full path to the module's parent directory on your USB to the PSModulePath as a process-level environment variable:
$portableModuleDirectory = [System.IO.DirectoryInfo]'./relative/path/to/dependent/module'
$env:PSModulePath += ";$(Split-Path -Parent $portableModuleDirectory.FullName)"
Import-Module ModuleName
However, this is cumbersome to have to do. The best solution here would be to host your own internal nuget feed to push your package to, so you can install the module on any machine you need it on from your network, if you can't upload it to the public PowerShell Gallery (which you should host your own feed/squid proxy for business needs).

Powershell Dot Slash .\ Starts at the root of a drive

Note: I'm using the built-in PowerShell ISE as my environment
I got a funny issue with dot slash on Powershell. All of my scripts run from a certain folder and there are subfolders that contain data that is needed for them to run.
For example, my scripts are saved at c:\users\chris\posh
Most of the time, I will call input and send output to subfolders like this...
c:\users\chris\posh\inputs
c:\users\chris\posh\output
Therefore I'll have scripts examples that look like this for inputs and outputs:
$hbslist = Get-Content .\inputs\HBS-IP.txt
write-output "$($lat),$($long)" | Out-File .\Outputs\"LatLong.csv" -Append
Lately, when I run the scripts, it cannot locate my files or exe's that I call on. That's because it's trying to look at P:/ instead of c:\users\chris\posh when using .\
Powershell also starts in my P:\ (mapped share drive) for some reason and I cannot figure out as to why my PC is running this way.
It might be a policy on your machine which changes your home directory. You can check the home directory with:
echo $env:HOME
This happens often on corporate machines. If you want to set it back for your powershell environment, you can set it in your profile.ps1.
This is typically stored at:
c:\Users\<Name>\Documents\WindowsPowershell\profile.ps1

How to load my custom PowerShell module? [duplicate]

I have to create a PowerShell script which does exactly same thing as my previous script, but this time I have to read a CSV file instead of an XML file. My plan is to create a PowerShell script which has common functions required for both scripts and re-use this common script file in both main files.
Suppose I create 2 main files in 2 directories in C:\ drive and keep my common file and other 3rd party libraries in a folder of D:\ drive, e.g. C:\script_1_folder\Script1.ps1, C:\script_2_folder\Script2.ps1 and common file and 3rd party libraries will be in D:\script_common.
How do I call\re-use common file in my main files (how to get the path, do I have to create an instance of common file and how do I use it)
What is the difference between
$script_path = $myinvocation.invocationname;
$script_folder = split-path $script_path -parent;
write-host $script_folder
$script_name = split-path $script_path -leaf;
$current_folder = [system.io.directory]::getcurrentdirectory()
[system.io.directory]::setcurrentdirectory($script_folder)
Set-Location $script_folder
add-type -path ".\AlexFTPS-1.1.0\AlexPilotti.FTPS.Client.dll"
and
$path = (split-path $MyInvocation.MyCommand.Path)
$loggerPath = $path + "\Logger\release\Logger.ps1";
.$loggerPath;
$logger = Logger;
$logger.load($path + "\Logger\config\log4ps.xml","log.log");
and what is the best way to do it with regard to my problem?
How do I create a temp folder in windows temp folder?
Common Code In Powershell
You can just put the code you want to include in a different PS1 file, and then "dot source" that file to include it in the current scope:
. D:\script_common\MyCode.ps1
That's all there is to that.
Using a Module
You might consider using a module instead, which can be included using the Import-Module cmdlet. You might have used this to work with things like Active Directory, where you could do something like this:
Import-Module ActiveDirectory
In that case, you only need the name of the module because it's in a special directory.
To write your own modules in Powershell, you name the module with a .psm1 extension. Typically, you don't do free floating code in one of these; you write functions which are then available to the code which imports the module.
To import a script module from anywhere, use the full path:
Import-Module D:\script_common\MyModule.psm1
Module Paths
When you create your own modules, you can keep them any old place and then refer to them by their full path (as above). There are also several locations that Powershell looks for modules:
$PSHome\Modules (%Windir%\System32\WindowsPowerShell\v1.0\Modules) -- Reserved for modules that ship with Windows. Do not put things here.
$Home\Documents\WindowsPowerShell\Modules (%UserProfile%\Documents\WindowsPowerShell\Modules)
%ProgramFiles%\WindowsPowerShell\Modules -- this isn't mentioned in the link, and seems to be used more for Desired State Configuration modules (probably because it applies to the entire system).
These are defaults, but Powershell uses its own environment variable called PSModulePath to determine where to look, and much like PATH you can add your own folder(s) to that variable.
That lets you keep your modules in your own location. Do see the link for more info on how to structure your folders and how to do naming.
So as far as keeping your modules and "3rd party" modules in the same place, that depends on the 3rd party stuff. It may install its own modules in its own place and modify the path, or it may just let you put them wherever you want.
Creating a Temp Folder
You can use the TEMP or TMP environment variables to get the path of the temp folder. To retrieve them in Powershell, use $env:TEMP or $env:TMP.
You'll have to come up with a unique name of a folder to create in there. One way to do that might be to use a GUID:
$dirName = [System.Guid]::NewGuid().ToString()
New-Item -Path "$($env:TEMP)\$dirName"
You should be able to dot source the script like that:
. "C:\script_common\script.ps1"
after that you can use all the functions like they were in the script you are running.
But... the better way to do it would be to create a module with your common functions (How to here: Scripting Guy´s Blog. (TLDR Version: place functions into psm1 file, put into modulepath, import using Import-Module, profit)
For creating a folder:
New-Item C:\Temp\yourfolder -type directory
Here is my attempt to create a template system in powershell : https://github.com/kayasax/PowershellTemplate
It allows to reuse functions you save in the repository by using tags in the template
eg :
<include logging/log>
The content of the file log.ps1 found in the logging directory of the function repository will be inserted when tranforming template to script

How can I re-use/import script code in PowerShell scripts?

I have to create a PowerShell script which does exactly same thing as my previous script, but this time I have to read a CSV file instead of an XML file. My plan is to create a PowerShell script which has common functions required for both scripts and re-use this common script file in both main files.
Suppose I create 2 main files in 2 directories in C:\ drive and keep my common file and other 3rd party libraries in a folder of D:\ drive, e.g. C:\script_1_folder\Script1.ps1, C:\script_2_folder\Script2.ps1 and common file and 3rd party libraries will be in D:\script_common.
How do I call\re-use common file in my main files (how to get the path, do I have to create an instance of common file and how do I use it)
What is the difference between
$script_path = $myinvocation.invocationname;
$script_folder = split-path $script_path -parent;
write-host $script_folder
$script_name = split-path $script_path -leaf;
$current_folder = [system.io.directory]::getcurrentdirectory()
[system.io.directory]::setcurrentdirectory($script_folder)
Set-Location $script_folder
add-type -path ".\AlexFTPS-1.1.0\AlexPilotti.FTPS.Client.dll"
and
$path = (split-path $MyInvocation.MyCommand.Path)
$loggerPath = $path + "\Logger\release\Logger.ps1";
.$loggerPath;
$logger = Logger;
$logger.load($path + "\Logger\config\log4ps.xml","log.log");
and what is the best way to do it with regard to my problem?
How do I create a temp folder in windows temp folder?
Common Code In Powershell
You can just put the code you want to include in a different PS1 file, and then "dot source" that file to include it in the current scope:
. D:\script_common\MyCode.ps1
That's all there is to that.
Using a Module
You might consider using a module instead, which can be included using the Import-Module cmdlet. You might have used this to work with things like Active Directory, where you could do something like this:
Import-Module ActiveDirectory
In that case, you only need the name of the module because it's in a special directory.
To write your own modules in Powershell, you name the module with a .psm1 extension. Typically, you don't do free floating code in one of these; you write functions which are then available to the code which imports the module.
To import a script module from anywhere, use the full path:
Import-Module D:\script_common\MyModule.psm1
Module Paths
When you create your own modules, you can keep them any old place and then refer to them by their full path (as above). There are also several locations that Powershell looks for modules:
$PSHome\Modules (%Windir%\System32\WindowsPowerShell\v1.0\Modules) -- Reserved for modules that ship with Windows. Do not put things here.
$Home\Documents\WindowsPowerShell\Modules (%UserProfile%\Documents\WindowsPowerShell\Modules)
%ProgramFiles%\WindowsPowerShell\Modules -- this isn't mentioned in the link, and seems to be used more for Desired State Configuration modules (probably because it applies to the entire system).
These are defaults, but Powershell uses its own environment variable called PSModulePath to determine where to look, and much like PATH you can add your own folder(s) to that variable.
That lets you keep your modules in your own location. Do see the link for more info on how to structure your folders and how to do naming.
So as far as keeping your modules and "3rd party" modules in the same place, that depends on the 3rd party stuff. It may install its own modules in its own place and modify the path, or it may just let you put them wherever you want.
Creating a Temp Folder
You can use the TEMP or TMP environment variables to get the path of the temp folder. To retrieve them in Powershell, use $env:TEMP or $env:TMP.
You'll have to come up with a unique name of a folder to create in there. One way to do that might be to use a GUID:
$dirName = [System.Guid]::NewGuid().ToString()
New-Item -Path "$($env:TEMP)\$dirName"
You should be able to dot source the script like that:
. "C:\script_common\script.ps1"
after that you can use all the functions like they were in the script you are running.
But... the better way to do it would be to create a module with your common functions (How to here: Scripting Guy´s Blog. (TLDR Version: place functions into psm1 file, put into modulepath, import using Import-Module, profit)
For creating a folder:
New-Item C:\Temp\yourfolder -type directory
Here is my attempt to create a template system in powershell : https://github.com/kayasax/PowershellTemplate
It allows to reuse functions you save in the repository by using tags in the template
eg :
<include logging/log>
The content of the file log.ps1 found in the logging directory of the function repository will be inserted when tranforming template to script