Import functions in a script with parameters - powershell

I have a script with parameters:
param (
[Parameter(Mandatory=$true)][string]$VaultName,
[Parameter(Mandatory=$true)][string]$SecretName,
[Parameter(Mandatory=$true)][bool]$AddToMono = $false
)
...
In this script I want to include functions that I wrote in another ps1 file : common.ps1
I usually import this with
. .\common.ps1
but if I do that in the script I get:
The term '.\common.ps1' 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.
How do I import common.ps1 in this script?
Thanks!

The problem is that you are running the script from a different directory. PowerShell is looking for .\common.ps1 using the current directory, not the directory of the script. To get around this, use the built-in variable $PSScriptRoot, which contains the path of the current script. (I'm assuming you are using PowerShell v3.0 or later.)
common.ps1
function foo {
return "from foo"
}
with_params.ps1
param (
[Parameter(Mandatory=$true)][string]$VaultName,
[Parameter(Mandatory=$true)][string]$SecretName,
[Parameter(Mandatory=$true)][bool]$AddToMono = $false
)
. $PSScriptRoot\common.ps1
Write-Output "Vault name is $VaultName"
foo
I then executed this:
PS> .\some_other_folder\with_params.ps1 -VaultName myVault -SecretName secretName -AddToMono $false
and got this output:
Vault name is myVault
from foo

Related

Azure Function - PowerShell, installing az cmdlet :: The term 'az' is not recognized as the name of a cmdlet

I am attempting to install the az cmdlet onto Kudu for my Azure Function. I am currently following this guide:
How to install a PowerShell module in an Azure Function
... however - I am still getting the following error within my Azure Function:
az : The term 'az' 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.
at run.ps1: line 1
Steps I have done till now:
Created a module folder under D:\home\site\wwwroot\Communication_with_Azure_Container_Registry\>
Within the module folder I have added the contents of azure-cli/2.0.35/..., (which looks like this):
... Azure Function code is very simple to proof out the ability to install the cmdlet:
if (-not (Get-Module -Name "az"))
{
Write-Output "azure-cli not installed";
}
else
{
Write-Output "azure-cli installed";
}
$test = 'az --help'
Invoke-Expression $test
Write-output `n$test
Question:
Is there something within my configuration that is not allowing for the az cmdlet to install?
Is there an alternative way to gain access to the azure-cli without implementing the node module?
I solved the following part of your problem
az : The term 'az' 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. at run.ps1: line 1
If you execute
Test-Path -Path 'C:\Program Files (x86)\Microsoft SDKs\Azure\CLI2\wbin'
You will probably get False. This means that you need to install the Azure CLI eg from https://learn.microsoft.com/en-us/cli/azure/install-azure-cli-windows?view=azure-cli-latest
I haven't testing this myself, but according to https://blogs.msdn.microsoft.com/powershell/2017/02/24/using-powershell-modules-in-azure-functions/ you should be able to do an Import-Module. In their example...
Write-Output “Loading Wunderlist Module”
import-module ‘D:\Home\site\wwwroot\HttpTriggerPowerShellDemo\Modules\Wunderlist\1.0.10\Wunderlist.psm1’
$Result = Get-Help Get-WunderlistUser | Out-String
Write-Output $Result
Install Azure CLI
https://learn.microsoft.com/en-us/cli/azure/install-azure-cli?view=azure-cli-latest
This should give you the az command

Passing Arguments between script files

I need to pass a few arguments from one script in file to another one. I load path to my current script file to variable and add name, arguments of other script that I want to call.
Here is the sample of calling and passing argument that I got in Script1.ps1:
Param([string]$argument)
$thisScript = Split-Path -Path $MyInvocation.MyCommand.Definition -Parent
.($thisScript+'\anotherScript.ps1 -passedArgument '+$argument)
Here is the part of the script Script2.ps1 that I'm calling:
Param([string]$passedArgument)
$passedArgument = "do some work with it HERE"
When I start the first script like this
C:\Users\user1\Desktop\Script1.ps1 -argument datatopass
it writes the error
The term 'C:\Users\user1\Desktop\Script2.ps1 -passedArgument datatopass' 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.
When I try use the script manually like this
C:\Users\user1\Desktop\Script2.ps1 -passedArgument datatopass
it works fine and doesn't report any error with wrong path or name.
I don't know where the problem is, and I couldn't find anything about this error.
You dont have to concat the passedArgument with its value to a string. Try:
& (Join-Path $thisScript 'anotherScript.ps1') -passedArgument $argument

How can my script call functions in another scripts in remote session?

Say I have two scripts:
Script 1:
helper.ps1 with contents:
#helper.ps1
Function foo
{
# do something
}
Script 2:
worker.ps1 with contents:
#worker.ps1
. 'c:\helper.ps1' # This is the correct file location, verified
Write-Output "Starting foo..."
foo
Write-Output "Done"
These two files are already uploaded to the remote server, and I try to run these using remote session with Invoke-Command:
Invoke-Command -ScriptBlock {
param($script)
& $script
} -Args 'worker.ps1'
It turns out most part of worker.ps1 is working correctly, in the above example, we will be able to get the output of line 1 and line 3.
However, it cannot run the function foo, with exception says that it is not function/script/anything, which basically means the helper.ps1 is not loaded correctly:
The term 'foo' 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.
The question is, is this the expected behavior? Can we not load other script in one script using remote session control, even when both files are uploaded and existed in the remote server?
Invoke command below:
Invoke-Command -ScriptBlock {param($script) & $script} -Args 'worker.ps1' .
Exception: The term 'foo' 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. I think Invoke-Command does what it does, since I got other lines executed without problem
I messed with this a bit and found the following to work:
worker.ps1 file:
#worker.ps1
. "c:\helper.ps1"
Write-Output "Starting foo..."
foo
Write-Output "Done"
helper.ps1 file:
#helper.ps1
Write-Host "Loading foo function..."
Function foo
{
# do something
Write-Host "The foo is alive!"
}
Write-Host "Foo loaded"
Command on remote system:
Invoke-Command -ScriptBlock {param($script) & $script} `
-ArgumentList 'c:\Worker.ps1' -ComputerName Machine
Output:
Loading foo function...
Foo loaded
Starting foo...
The foo is alive!
Done
So it may just be an issue with the single quotes instead of double quotes around the filename. I was able to execute the Invoke-Command block from two different systems to this machine and had the same results on both. (All my systems are running PS v4 so you may see different results on PS v3.)

$MyInvocation.MyCommand.Name Providing Strange Results

Why does $MyInvocation.MyCommand.Name give you the name of the function when executed from within a function?
According to this it is meant to give you the script file name.
Here is the code I'm using:
function startScript
{
$ScriptName = $MyInvocation.MyCommand.Name
$ScriptName
}
$ScriptName = $MyInvocation.MyCommand.Name
$ScriptName
startScript
<#
Output:
testing.ps1
startScript
#>
According to PowerShell documentation:
$MyInvocation
Contains an information about the current command, such as the name,
parameters, parameter values, and information about how the command was
started, called, or "invoked," such as the name of the script that called
the current command.
$MyInvocation is populated only for scripts, function, and script blocks.
You can use the information in the System.Management.Automation.InvocationInfo
object that $MyInvocation returns in the current script, such as the path
and file name of the script ($MyInvocation.MyCommand.Path) or the name of a
function ($MyInvocation.MyCommand.Name) to identify the current command.
This is particularly useful for finding the name of the current script.
Also see the following paragraph if you are interested in the script path:
Beginning in Windows PowerShell 3.0, $MyInvocation has the following new
properties.
-- PSScriptRoot: Contains the full path to the script that invoked the
current command. The value of this property is populated only when
the caller is a script.

How can I use an Environmental Variable as a start of a directory location in powershell?

I was given a powershell script by a coworker to try and figure out. I have very little expereince with it so I've gotten stuck.
We need to pull a user defined cmdlet from a .ps1 file form another part of the drive.
Normally you would do it something like this:
. .\scripts\thing.ps1
But we want to use an environmental variable set in command prompt to start the location. We have something like:
. $Env:JobDir\scripts\thing.ps1
But this returns the error
. : The term '\scripts\thing.ps1' is not recognized as the name of a cmdlet, function, script file, or operable program.
Is there anyway to make something like this work?
You'd need to make it a string, otherwise it's interpreting the entire path as a variable.
"$Env:JobDir\scripts\thing.ps1"
or
$Env:JobDir + "\scripts\thing.ps1"
You can do something like this:
# build the path to the job
$job = Join-path -Path $Env:JobDir -ChildPath "scripts\thing.ps1"
# execute the job
$job
or
.$("$Env:JobDir\scripts\thing.ps1")