I created a cmdlet *.ps1 file with a single function Backup-Data that I load into my $profile with Import-Module Backup-Data.ps1.
Everytime I test it, I save the file and reopen the powershell console but this process is very tedious. So, I was wondering whether there is a way to call that directly from the console?
Unless you're defining new types in the Backup-Data.ps1 script, the following should suffice for restarting your testing in an interactive session:
Remove-Module Backup-Data -Force
Import-Module Backup-Data.ps1
Related
I wrote a script to build all .net projects in a folder.
Issue
The issue is I am getting a missing function error when I call Build-Sollution.
What I tried
I made sure that function was declared before I used it so I am not really sure why it saids that it is not defined.
I am new to powershell but I would think a function calling another functions should work like this?
Thanks in advance!
Please see below for the error message and code.
Error Message
Line |
3 | Build-Sollution $_
| ~~~~~~~~~~~~~~~
The term 'Build-Sollution' is not recognized as the name of a cmdlet, function, script file, or operable program.
Check the spelling of the name, or if a path was included, verify that the path is correct and try again.
Build-Sollution:
Code
param (
#[Parameter(Mandatory=$true)][string]$plugin_path,
[string]$depth = 5
)
$plugin_path = 'path/to/sollutions/'
function Get-Sollutions {
Get-ChildItem -File -Path $plugin_path -Include *.sln -Recurse
}
function Build-Sollution($solution) {
dotnet build $solution.fullname
}
function Build-Sollutions($solutions) {
$solutions | ForEach-Object -Parallel {
Build-Sollution $_
}
}
$solutions_temp = Get-Sollutions
Build-Sollutions $solutions_temp
From PowerShell ForEach-Object Parallel Feature | PowerShell
Script blocks run in a context called a PowerShell runspace. The runspace context contains all of the defined variables, functions and loaded modules.
...
And each runspace must load whatever module is needed and have any variable be explicitly passed in from the calling script.
So in this case, the easiest solution is to define Build-Sollution inside Build-Sollutions
As for this...
I am new to powershell but I would think a function calling another
functions should work like this?
... you cannot use the functions until you load your code into memory. You need to run the code before the functions are available.
If you are in the ISE or VSCode, if the script is not saved, Select All and hit use the key to run. In the ISE use F8 Selected, F5 run all. In VSCode, F8 run selected, crtl+F5 run all. YOu can just click the menu options as well.
If you are doing this from the consolehost, the run the script using dot sourcing.
. .\UncToYourScript.ps1
It's ok to be new, we all started somewhere, but it's vital that you get ramped up first. so, beyond what I address here, be sure to spend time on Youtube and search for Beginning, Intermediate, Advanced PowerShell for videos to consume. There are tons of free training resources all over the web and using the built-in help files would have given you the answer as well.
about_Scripts
SCRIPT SCOPE AND DOT SOURCING Each script runs in its own scope. The
functions, variables, aliases, and drives that are created in the
script exist only in the script scope. You cannot access these items
or their values in the scope in which the script runs.
To run a script in a different scope, you can specify a scope, such as
Global or Local, or you can dot source the script.
The dot sourcing feature lets you run a script in the current scope
instead of in the script scope. When you run a script that is dot
sourced, the commands in the script run as though you had typed them
at the command prompt. The functions, variables, aliases, and drives
that the script creates are created in the scope in which you are
working. After the script runs, you can use the created items and
access their values in your session.
To dot source a script, type a dot (.) and a space before the script
path.
See also:
'powershell .net projects build run scripts'
'powershell build all .net projects in a folder'
Simple build script using Power Shell
Update
As per your comments below:
Sure the script should be saved, using whatever editor you choose.
The ISE does not use PSv7 by design, it uses WPSv5x and earlier.
The editor for PSv7 is VSCode. If you run a function that contains another function, you have explicitly loaded everything in that call, and as such it's available.
However, you are saying, you are using PSv7, so, you need to run your code in the PSv7 consolehost or VSCode, not the ISE.
Windows PowerShell (powershell.exe and powershell_ise.exe) and PowerShell Core (pwsh.exe) are two different environments, with two different executables, designed to run side-by-side on Windows, but you do have to explicitly choose which to use or write your code to branch to a code segment to execute relative to the host you started.
For example, let's say I wanted to run a console command and I am in the ISE, but I need to run that in Pwsh. I use a function like this that I have in a custom module autoloaded via my PowerShell profiles:
# Call code by console executable
Function Start-ConsoleCommand
{
[CmdletBinding(SupportsShouldProcess)]
[Alias('scc')]
Param
(
[string]$ConsoleCommand,
[switch]$PoSHCore
)
If ($PoSHCore)
{Start-Process pwsh -ArgumentList "-NoExit","-Command &{ $ConsoleCommand }" -PassThru -Wait}
Else {Start-Process powershell -ArgumentList "-NoExit","-Command &{ $ConsoleCommand }" -PassThru -Wait}
}
All this code is doing is taking whatever command I send it and if I use the PoSHCore switch...
scc -ConsoleCommand 'SomeCommand' -PoSHCore
... it will shell out to PSCore, run the code, otherwise, it just runs from the ISE>
If you want to use the ISE with PSv7 adn not do the shell out thing, you need to force the ISE to use PSv7 to run code. See:
Using PowerShell Core 6 and 7 in the Windows PowerShell ISE
Is there a way to specify which PowerShell profile to load when initializing PowerShell?
For instance, I'd like to be able to load a Python Conda profile when working in Python, or load a profile with bash command aliases when working with cross-platform scripts.
Note: I'm on the same machine, on the same user. So machine/user-specific profiles would not work in my case.
As PowerShell profiles are just PowerShell scripts loaded on startup of the PowerShell terminal, there are multiple ways to load them. Assuming you have two profile files:
conda_profile.ps1
bash_profile.ps1
Calling the profile scripts directly
You can just execute them after you open a PowerShell window, e. g.:
.\conda_profile.ps1
Calling the profile scripts by aliases
If the names or paths are too long or too complicated, you can create aliases for them, e. g.:
# Put the following two lines into the file stored in $PROFILE. You probably have to create it.
Set-Alias -Name condap -Value "C:\path\to\conda_profile.ps1"
Set-Alias -Name bashp -Value "C:\path\to\bash_profile.ps1"
After that, you can load a profile by typing condap or bashp.
Calling a profile by shortcut
You can also create different shortcuts to open a PowerShell with a certain profile:
Copy the shortcut from %APPDATA%\Microsoft\Windows\Start Menu\Programs\Windows PowerShell\Windows PowerShell.lnk
Rename it to condap for example.
Edit its target from %SystemRoot%\system32\WindowsPowerShell\v1.0\powershell.exe to %SystemRoot%\system32\WindowsPowerShell\v1.0\powershell.exe -ExecutionPolicy Bypass -NoExit -File "C:\path\to\conda_profile.ps1".
Do it for other profiles respectively.
Choosing a profile by being prompted at startup
You can also write a profile that asks you to choose between different profiles, when you start PowerShell. Make sure you have a profile for your current host and current user:
if (!(Test-Path -Path $PROFILE)) {
New-Item -Type File -Path $PROFILE -Force
}
After that, add some lines to this file to ask for input and execute the desired profile script based on that input. It will work, but keep in mind that a user interaction inside the profile will probably be a bad design in the most cases.
Just to be more concise for command line (and non-windows) users:
pwsh -NoExit -File <your_profile_script>
Will start a powershell session with the specified profile.
What's the difference between Start-Process and Invoke-Item? I noticed that you can't Invoke-Item chrome. I assume that Invoke-Item is specifically for files with a given file path. But are there any advantages to using Invoke-Item instead of Start-Process (besides that typing ii is faster than typing start)?
The Invoke-Item cmdlet performs the default action on the specified item. For example, it runs an executable file or opens a document file in the application associated with the document file type. The default action depends on the type of item and is determined by the PowerShell provider that provides access to the data.
https://learn.microsoft.com/en-us/powershell/module/microsoft.powershell.management/invoke-item?view=powershell-6
The Start-Process cmdlet starts one or more processes on the local computer. To specify the program that runs in the process, enter an executable file or script file, or a file that can be opened by using a program on the computer. If you specify a non-executable file, Start-Process starts the program that is associated with the file, similar to the Invoke-Item cmdlet.
You can use the parameters of Start-Process to specify options, such as loading a user profile, starting the process in a new window, or using alternate credentials.
https://learn.microsoft.com/en-us/powershell/module/Microsoft.PowerShell.Management/Start-Process?view=powershell-6
I want to have several (more than one) PowerShell profiles which will create different environments.
More specifically I need way for start separate PowerShell ISE for work with TFS and other PowerShell ISE instance for regular work. 'TFS' environment require loading some additional snappins, modules, modify prompt and so on. I do not want all this stuff will be executed for regular PowerShell ISE sessions but only when I want to.
I found that I can automatically load arbitrary script through command line parameter -File, but it does not executed automatically..
I do it by creating a shortcut for PowerShell ISE with a default directory :
In the default Directory (here called D:\TFS) I create a .PS1 file called local_profile.ps1.
In the beginning of the current profile file (C:\Windows\System32\WindowsPowerShell\v1.0\profile.ps1) I add :
# Try to load local profile
Get-ChildItem "local_profile.ps1" -ErrorAction SilentlyContinue | %{.$_}
You just have to add your initialization code to D:\TFS\local_profile.ps1.
powershell ISE has a profile too.
Probably is something like:
E:\Users\UserName\Documents\WindowsPowerShell\Microsoft.PowerShellISE_profile.ps1
Or you can open powershell ise and look at $profile variable.
After locate your profile file, write your modules import and custom scripts in it.
I encountered a challenge that I failed to resolve the way I wanted it to do.
I got a file that contains a powershell script, but that file does not have the extension assigned to powershell. The question is: How can I execute a powershell in a script file with the wrong file extension (or none)?
Invoke-Expression does not seem to work because it always executes the default action assigned to the file type. If I give that cmdlet a *.txt file the editor pops open.
I know that I can resolve that by renaming the script file or naming it properly in the first place. This is what I ended up doing.
Still I wonder if it is possible to execute a file as a script with the wrong file extension without modifying, renaming or coping the file. And if it is not working… why is that?
Powershell is designed such that executing or dot sourcing a file requires a .ps1 extension, and Powershell.exe will refuse to run any file that doesn't have that extension.
One way to invoke Powershell code from a non-ps1 file is to launch Powershell.exe using STDIN, and pipe your script to it. This requires a new shell, so is not very good for launching scripts from within an existing scripting environment.
Powershell.exe - < thescript.txt
Another way is to create a temporary .ps1 file and execute that. This has the advantage of using the current scripting environment, but requires a temporary file.
Copy-Item -Path '.\thescript.txt' -Dest '.\temp.ps1'
. .\temp.ps1
del .\temp.ps1
In my opinion, the file extension restriction is silly, but that's how it was designed. Apocryphally, this is for security reasons, but I can find no citation to back it up.
Or you use Get-Content to read the file and then invoke that with Invoke-Expression or Invoke-Command -ScriptBlock.