Shorter execution of powershell script - powershell

Say I have a script to be executed in a single call, how do I do it?
Like, say I have a powershell script saved at E:\Fldr\scrpt.ps1.
Now if I have to normally execute that script is PowerShell ISE then I would have to use:
& "E:\Fldr\scrpt.ps1"
and the scrpt.ps1 gets executed.
But whatI want is, when I write a word, say "exeScrpt" instead of & "E:\Fldr\scrpt.ps1" then I want scrpt.ps1 to get executed.
Is there a way to do this?
Thank you for checking in..

You can wrap your call to the script in a function:
function Invoke-Script
{
E:\Fldr\scrpt.ps1
}
Then you can run your script by executing a single command anywhere after the definition:
Invoke-Script
Note that it is good practice to name your functions according to the Verb-Noun cmdlet naming standard, so something like Invoke-Script instead of exeScrpt. If you really want a single word as the name, then you can additionally create an alias for your function:
New-Alias -Name exeScrpt -Value Invoke-Script

Related

Inbuilt function in *.ps1 is not recognizing [duplicate]

I have a powershell script that parses a file and send an email if it detects a certain pattern. I have the email code setup inside a function, and it all works fine when I run it from the ISE, but I used PS2EXE to be able to run the script as a service but it does not recognize the function "email". my code looks similar to this
#Do things |
foreach{
email($_)
}
function email($text){
#email $text
}
When I convert it to exe and run it I get this error:
The term 'email' is not recognized as teh 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.
Powershell processes in order (top-down) so the function definition needs to be before the function call:
function email($text){
#email $text
}
#Do things |
foreach{
email($_)
}
It probably works fine in the ISE because you have the function definition in memory still from a prior run or test.
When it comes to the Function-Calls, PowerShell is fairly different from other programming-languages in the following ways:
When passing the arguments to a function, parentheses are NOT allowed (and will raise a parse error if Set-StrictMode is set to -version 2.0 or above/Latest), however, Parenthesised arguments must be used to call a method, which can either be a .NET method or a user defined method (defined within a Class - in PS 5.0 or above).
Parameters are space-separated and not comma separated.
Be careful in where you define the function. As PowerShell sequentially processes line-by-line in top-down order, hence the function must be defied before that function is called:
Function func($para1){
#do something
}
func "arg1" #function-call
In Windows PowerShell ISE (or Visual Studio Code) if a function-call appears to be working even though the function-definition is defined below the function-call, (beware) this is because it's cached in memory from a previous execution(s), which too will fail as soon as you update the function-definition.

How to load custom powershell profile with single command

I have a shared computer for which I want to create a custom PowerShell profile that I can load with a simple command but which otherwise never gets sourced.
I tried adding a function like this to the main $profile:
function custom() {. C:\Users\[username]\Documents\WindowsPowerShell\custom_profile.ps1}
The idea was that I could just type the command custom and it would load my custom profile.
This doesn't work, because it does the sourcing inside the function scope, and all of the functions and aliases are lost when I leave that scope.
I could just execute the entire . C:\Users\[username]\Documents\WindowsPowerShell\custom_profile.ps1 command, but I am looking for a way to do this with a single command.
If I were in bash, I'd just use something like alias custom=". C:\Users\[username]\Documents\WindowsPowerShell\custom_profile.ps1", but Powershell's alias doesn't work that way.
How can I do this in PowerShell?
Or, change the file to a psm1 (a powershell module) and then :
Function custom {
if(-not Get-Module custom_profile){
Import-Module 'C:\Users\[username]\Documents\WindowsPowerShell\custom_profile.psm1'
} else {
Remove-Module custom_profile
Import-Module 'C:\Users\[username]\Documents\WindowsPowerShell\custom_profile.psm1'
}
}
and then running
custom
will do what you want.
As noted in the comments you might need
Export-ModuleMember -Variable * -Function * -Alias *
if your module is supposed to export variables and aliases as well as functions.
A simple way might be to just use a variable instead of a function.
In profile:
$custom = 'C:\Users\[username]\Documents\WindowsPowerShell\custom_profile.ps1'
Interactively:
. $custom
Probably want to use a better name that's less likely to be overwritten, but same concept.
The most simple way would be to use PSReadLine, define your own handler to be executed, such as F5 to load custom prifile.
This is shorter then writing a command also as you have to press 1 key.
You should use PSReadLine anyway as it overpowers stock console in every aspect.

Referencing text after script is called within PS1 Script

Let's take the PowerShell statement below as an example:
powershell.exe c:\temp\windowsbroker.ps1 IIS
Is it possible to have it scripted within windowsbroker.ps1 to check for that IIS string, and if it's present to do a specific install script? The broker script would be intended to install different applications depending on what string followed it when it was called.
This may seem like an odd question, but I've been using CloudFormation to spin up application environments and I'm specifying an "ApplicationStack" parameter that will be referenced at the time when the powershell script is run so it knows which script to run to install the correct application during bootup.
What you're trying to do is called argument or parameter handling. In its simplest form PowerShell provides all arguments to a script in the automatic variable $args. That would allow you to check for an argument IIS like this:
if ($args -contains 'iis') {
# do something
}
or like this if you want the check to be case-sensitive (which I wouldn't recommend, since Windows and PowerShell usually aren't):
if ($args -ccontains 'IIS') {
# do something
}
However, since apparently you want to use the argument as a switch to trigger specific behavior of your script, there are better, more sophisticated ways of doing this. You could add a Param() section at the top of your script and check if the parameter was present in the arguments like this (for a list of things to install):
Param(
[Parameter()]
[string[]]$Install
)
$Install | ForEach-Object {
switch ($_) {
'IIS' {
# do something
}
...
}
}
or like this (for a single option):
Param(
[switch]$IIS
)
if ($IIS.IsPresent) {
# do something
}
You'd run the script like this:
powershell "c:\temp\windowsbroker.ps1" -Install "IIS",...
or like this respectively:
powershell "c:\temp\windowsbroker.ps1" -IIS
Usually I'd prefer switches over parameters with array arguments (unless you have a rather extensive list of options), because with the latter you have to worry about spelling of the array elements, whereas with switches you got a built-in spell check.
Using a Param() section will also automatically add a short usage description to your script:
PS C:\temp> Get-Help windowsbroker.ps1
windowsbroker.ps1 [-IIS]
You can further enhance this online help to your script via comment-based help.
Using parameters has a lot of other advantages on top of that (even though they probably aren't of that much use in your scenario). You can do parameter validation, make parameters mandatory, define default values, read values from the pipeline, make parameters depend on other parameters via parameter sets, and so on. See here and here for more information.
Yes, they are called positional parameters. You provide the parameters at the beginning of your script:
Param(
[string]$appToInstall
)
You could then write your script as follows:
switch ($appToInstall){
"IIS" {"Install IIS here"}
}

Powershell script not recognizing my function

I have a powershell script that parses a file and send an email if it detects a certain pattern. I have the email code setup inside a function, and it all works fine when I run it from the ISE, but I used PS2EXE to be able to run the script as a service but it does not recognize the function "email". my code looks similar to this
#Do things |
foreach{
email($_)
}
function email($text){
#email $text
}
When I convert it to exe and run it I get this error:
The term 'email' is not recognized as teh 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.
Powershell processes in order (top-down) so the function definition needs to be before the function call:
function email($text){
#email $text
}
#Do things |
foreach{
email($_)
}
It probably works fine in the ISE because you have the function definition in memory still from a prior run or test.
When it comes to the Function-Calls, PowerShell is fairly different from other programming-languages in the following ways:
When passing the arguments to a function, parentheses are NOT allowed (and will raise a parse error if Set-StrictMode is set to -version 2.0 or above/Latest), however, Parenthesised arguments must be used to call a method, which can either be a .NET method or a user defined method (defined within a Class - in PS 5.0 or above).
Parameters are space-separated and not comma separated.
Be careful in where you define the function. As PowerShell sequentially processes line-by-line in top-down order, hence the function must be defied before that function is called:
Function func($para1){
#do something
}
func "arg1" #function-call
In Windows PowerShell ISE (or Visual Studio Code) if a function-call appears to be working even though the function-definition is defined below the function-call, (beware) this is because it's cached in memory from a previous execution(s), which too will fail as soon as you update the function-definition.

Execute a parameter passed into a powershell script as if it were a line in the script

I've got a wrapper powershell script that I'm hoping to use to automate a few things. It's pretty basic, and accepts a parameter that I want the script to run as if it were a line in the script. I absolutely cannot get it to work.
example:
param( [string[]] $p)
echo $p
# Adds the base cmdlets
Add-PSSnapin VMware.VimAutomation.Core
# Add the following if you want to do things with Update Manager
Add-PSSnapin VMware.VumAutomation
# This script adds some helper functions and sets the appearance. You can pick and choose parts of this file for a fully custom appearance.
. "C:\Program Files (x86)\VMware\Infrastructure\vSphere PowerCLI\Scripts\Initialize-VIToolkitEnvironment.ps1"
$p
In the example above, I want $p to execute as if it were a line in the script. I know this isn't secure, and that's probably where the problem lies.
Here is how I try running the script and passing in a parameter for $p:
D:\ps\test>powershell -command "D:\ps\test\powershell_wrapper.ps1" 'Suspend-VM servername -Verbose -Confirm:$False'
How can I get my parameter of 'Suspend-VM servername -Verbose -Confirm:$False' to run inside my script? If I just include the value in the script instead of pass it in as a parameter it runs without any issues...
You can basically approach this two ways, depending on what your needs really are and how you want to structure your code.
Approach #1 - Invoke-Expression
Invoke-Expression basically allows you to treat a string like an expression and evaluate it. Consider the following trivial example:
Invoke-Expression '{"Hello World"}'
That will evaluate the string as if it were an expression typed in directly, and place the string "Hello World" on the pipeline. You could use that to take your string parameter and run it on-the-fly in your script.
Approach #2 - Using a ScriptBlock
PowerShell has a special data type called a ScriptBlock, where you can bind a script to a variable, and then invoke that script as part of your code. Again, here is a trivial example:
function Test-SB([ScriptBlock]$sb) {
$sb.Invoke()
}
Test-SB -sb {"Hello World"}
This example creates a function with a single parameter $sb that is of type ScriptBlock. Notice the parameter is bound to the actual chunk of code {"Hello World"}? That code is assigned to the $sb parameter, and then a call to the .Invoke method actually executes the code. You could adapt your code to take in a ScriptBlock and invoke it as part of your script.
Approach #3 - Updating your profile
OK, so I said there were two ways to approach it. There is actually a third... sort of... You could add the VMWare cmdlets to your $profile so they are always present and you don't need your wrapper to load in those libraries. Granted, this is a pretty big hammer - but it might make sense if this is the environment you are constantly working in. You could also just create a shortcut to PowerShell that runs a .ps1 on startup that includes those libraries and hangs around (this is what MS did with the SharePoint admin shell and several others). Take a look at this TechNet page to get more info on the $profile and if it can help you out:
http://msdn.microsoft.com/en-us/library/windows/desktop/bb613488.aspx