PowerShell - My first attempt at a function can't find the function - function

Trying to include a function in a PowerShell script. I get the message that the function does not exist.
I have the function just below where I am creating the parameters. I assume I'm missing something. I have a number of folders that I want to backup and want to call the function for each folder.
CODE STARTS HERE (code above and pram creation left off for brevity).
$ImagesSaveTo = "s3://crisma-backup/HERTRICH/Milford/$dow/images"
#
# Call Backup
BackupCrismaByShop -$LogFile $CrismaSource $CrismaSaveTo $ImagesSource
# Begin Backup Function
# ------------------------------------------------------------------------
function BackupCrismaByShop {
param(
[string]$LogFile,
[string]$CrismaSource,
[string]$CrismaSaveTo,
[string]$ImagesSource
)
# Backup script....
}

Powershell is a language which is interpreted, it means files are read top to bottom and being interpreted as if we speak.
So, if function is called before you have defined it, the Powershell interpreter does not know what you are talking about.
You can try to reorder your code and this should do the trick:
# DEFINE FUNCTION
function BackupCrismaByShop {
param(
[string]$LogFile,
[string]$CrismaSource,
[string]$CrismaSaveTo,
[string]$ImagesSource
)
# Backup script....
}
# YOUR VARIABLES AND OTHER STUFF
$ImagesSaveTo = "s3://crisma-backup/HERTRICH/Milford/$dow/images"
# CALLING THE FUNCTION
BackupCrismaByShop -$LogFile $CrismaSource $CrismaSaveTo $ImagesSource
I can imagine you are using Powershell ISE to code. Let me suggest you to try Visual Studio Code. It would provide you with some recommendations and warnings as you code such variables you are not using, functions called but not still defined, etc.
Thanks.

Related

Run Octave function with one argument from batch

I am trying to run an octave function from a batch file. The function is well written given how it works when launched from within the Octave GUI.
The batch file, other than pointing to the octave function, defines the only argument needed by it.
A while back this was not a function but a simple Octave script and the commands used were ok.
The only issue I am encountering now is being able to pass the variable calculated by the batch file onto the octave function.
I have recently written an octave function to do some file management. It requires only one input from the user:
function replace_TMM (file_base)
where file_base is a string to specify what directory I am working on. So it has to be something like "Z:" or "I:" or so on.
I am quite sure that the function is well written since I am able to use it from Octave GUI without any issues.
The fact is that I would like to run this function from a batch file. Inside this batch file I wrote:
SET a=%cd:~0,2%
This command is able to identify the working directory so "a" will be equal to "Z:" or similars.
Now my issue is telling the batch file to evaluate the octave function using "a" as its input argument.
I tried stuff like:
"C:\Program Files\GNU Octave\Octave-7.3.0\mingw64\bin\octave-cli.exe" -q --eval _03_REPLACE_V04("'%cd:~0,2%'")
which does not seem to work. This kind of solution gives a syntax error at batch level, it is not even able to enter the octave file.
If I instead try something like:
"C:\Program Files\GNU Octave\Octave-7.3.0\mingw64\bin\octave-cli.exe" -q _03_REPLACE_V04.m Z:
It is able to enter the octave file but it does not process the function, just skips over it to get to the end of the script.
Same goes if I try the following:
"C:\Program Files\GNU Octave\Octave-7.3.0\mingw64\bin\octave-cli.exe" _03_REPLACE_V04.m -"Z:"
In brief I bvelieve that the function itself works, it is only a matter of passing a variable from the batch to the octave.
Would really appreciate some help, thanks in advance.
UPDATE 1
I have done what was suggested by #Dariush Gavari and used the following syntax:
"C:\Program Files\GNU Octave\Octave-7.3.0\mingw64\bin\octave-cli.exe" -q --eval "replace_TMM('%a%')"
This gets me the following error message:
error: 'replace_TMM' undefined near line 1, column 1
I believed that it was because it was not ablòe to find the script containing the function. This is saved in a file called _03_REPLACE_V04.m
For this reason I have tried with
"C:\Program Files\GNU Octave\Octave-7.3.0\mingw64\bin\octave-cli.exe" -q --eval _03_REPLACE_V04.m "replace_TMM('%a%')"
Leading to the following error:
error: --eval "CODE" and script file are mutually exclusive options
usage: octave [-HVWdfhiqvx] [--debug] [--doc-cache-file file] [--echo-commands]
[--eval CODE] [--exec-path path] [--experimental-terminal-widget]
[--gui] [--help] [--image-path path] [--info-file file]
[--info-program prog] [--interactive] [--line-editing] [--no-gui]
[--no-history] [--no-init-file] [--no-init-path] [--no-line-editing]
[--no-site-file] [--no-window-system] [--norc] [-p path]
[--path path] [--persist] [--server] [--silent] [--traditional]
[--verbose] [--version] [file]
I believed that the problem could also have been having the functional nd the file with two different names. To solve this I have kept the same file name but changed the function to match it:
function _03_REPLACE_V04 (file_base)
Then in the batch:
"C:\Program Files\GNU Octave\Octave-7.3.0\mingw64\bin\octave-cli.exe" -q --eval "_03_REPLACE_V04('%a%')"
Leading to:
warning: function '_03_REPLACE_V04' defined within script file '\99_TOOLS\OCTAVE_FILES\_03_REPLACE_V04.m'
error: invalid call to script \99_TOOLS\OCTAVE_FILES\_03_REPLACE_V04.m
error: called from
_03_REPLACE_V04
In other words still no way of making it work. :)
Octave provides the argv function, which returns a cellstring array of all arguments passed to the octave executable at the time of launch, or in the case where it was used to launch a script, then this is the script's arguments.
So presumably all you have to do to get your directory from within octave is argv(){1}
If you would like to convert your filename to an absolute filename, you could also do this from within octave via the make_absolute_filename function.
Incidentally, a very useful command you should know of in octave is the lookfor command. Writing lookfor arguments in the terminal returns a list with all functions which have the word "arguments" in their description; argv is at the top of that list.
You can then do help argv to see more details on that command.

Putting functions in separate script and dot-sourcing them - what will the scope be

I've put my functions in a separate file and I call the file with:
$workingdir = Split-Path $MyInvocation.MyCommand.Path -Parent
. "$workingdir\serverscan-functions.ps1"
But, if I call the scripts like
my-function
how will the variable scope (from within "my-function") be?
Should I still $script:variable to make the variable exist outside the function or have I dot-sourced the function as well?
Hope I don't confuse anyone with my question... I've tried to make it as understandable as possible, but still learning all the basic concept so I find it hard to explain..
When you dot source code it will behave as if that code was still in the original script. The scopes will be the same as if it was all in one file.
C:\functions.ps1 code:
$myVariable = "Test"
function Test-DotSource {
$script:thisIsAvailableInFunctions = "foo"
$thisIsAvailableOnlyInThisFunction = "bar"
}
main.ps1 code
$script:thisIsAvailableInFunctions = ""
. C:\functions.ps1
# Call the function to set values.
Test-DotSource
$script:thisIsAvailableInFunctions -eq "foo"
# Outputs True because of the script: scope modifier
$thisIsAvailableOnlyInThisFunction -eq "bar"
# Outputs False because it's undefined in this scope.
$myVariable -eq "Test"
# Outputs true because it's in the same scope due to dot sourcing.
In order to achieve what you want, you'll probably need to create a module. In the module, export the functions using Export-ModuleMember, and as long as you don't explicitly export any variables as module members, you should be fine.
Once you've created the module, import it using the Import-Module cmdlet.
My 2cents:
Usually (after a past Andy Arismendi answer! God bless you man!) I save all my scripts in $pwd folder (added in system path environment). The I can call them from the console wihtout dot sourcing and no script variable poisoning the console after a script ends his job.
If you cannot modify yours functions in simple scripts (sometimes it happens) I'm agree with Trevor answer to create a module and import it in $profile

Directing output to stdout in a function without the calling code seeing it

I wrote several Powershell scripts which deploy software for a client. I used Write-Host to output a lot of information so that the progress of the deploy can be watched and they call this from one of their deploy application using Start-Transcript to capture this output.
However, they also need to be able to call some of these scripts from another application which can only capture output from stdout. This means that Write-Host won't work there since it outputs only to the console or host and doesn't get directed to stdout (correct?)
My thought was that I could change the code to use Write-Out instead, except that this causes another problem. Since I use functions and since functions in Powershell "return" everything that goes to stdout to the caller that would likely screw up any of my code that retrieves output from a function.
Is there a way to direct output to stdout from a function without it going to the calling code as the output of the function itself? Here is an example of the problem:
function Test-Output ([int]$number) {
Write-Output "This is a string"
return $number
}
[int]$someNumber = Test-Output 10
$someNumber
If you run the code above you'll see an error because Powershell is trying to assign "This is a string" to the integer $someNumber. If you change the variable to a string then it will capture the full output of the function (This is a string 10) and assign it to the variable.
Thanks for any suggestions that you can give!
Function output and stdout are the same thing so the calling code is going to see anything output to the stdout stream. In this case I would suggest using the Write-Progress cmdlet to report progress to the end user and leave actual function output alone.
Try this.
function Add-Numbers {
param (
[double] $FirstNumber,
[double] $SecondNumber
)
Write-Host "Hello World"
return ($FirstNumber + $SecondNumber)
}
$result = Add-Numbers 1 2
#Write-Host "Result is $result"

Is there something equivalent to C's #include in Octave?

Suppose that I have 2 scripts:
magic_function.m:
function retval = magic(x)
retval = 12345678;
endfunction
other_script.m
#some code
X = magic(17)
What should I add to other_script.m in order to make function "magic" visible?
Judging by the documentation of Functions and Script Files, it should be sufficient to put the function in a file named magic.m in a directory specified in LOADPATH.
When Octave encounters an identifier that is undefined, it first looks
for variables or functions that are already compiled and currently
listed in its symbol table. If it fails to find a definition there, it
searches the list of directories specified by the built-in variable
LOADPATH for files ending in `.m' that have the same base name as the
undefined identifier.(4) Once Octave finds a file with a name that matches, the contents of the file are read. If it defines a single
function, it is compiled and executed.

Is there a way to pass params to a script in TCL that is run using eval source?

I have a script that calls:
eval source \{$scriptfile\}
where $scriptfile is another TCL script. Is there way to pass parameters to the script? I'd like to do something like:
set sampleData "ID=14678934"
eval source \{$scriptfile\} $sampleData
I know that this isn't allowed but, is there a way to pass data to a script that is being executed using eval source?
That's a horrible practice to start. It's much cleaner to call a proc that is within the script you're sourcing.
source script.tcl ;# defines proc run_script_with_data
run_script_with_data $data
The solution is given in the Tclers Wiki, in the following articles: source with args and SrcFile.
The solution I like the most is srcfile:
proc srcfile { filename args } {
global argv
set argv $args
source $filename
}
The only drawback of this approach is that it will modify argv, so you have to make sure you will not need it in the rest of the script, or backup and restore it.