Need Help - First Function - function

I'm trying to write my first function and am having some issues. When I run the below I get no output. I feel like I'm missing something obvious but I'm not sure what.
function findModifiedFiles {
[CmdletBinding()]
param (
[string]$dir,
[int]$days
)
Process {
Write-Host "Directory: " $dir
Write-Host "Days: "$days
}
}
Output:

You ultimately need to load your function and then call the function to receive any output. Since your function is defined in a file, one way to load the function is by dot sourcing the file. Then you can simply call your function.
. .\modfilesTest.ps1
findModifiedFiles -dir c:\temp -days 7
An alternative is to not use a function at all just run the script with parameters. If we edit your file to contain the following, we can just call the script afterwards.
# modfilesTest.ps1 Contents
[CmdletBinding()]
param (
[string]$dir,
[int]$days
)
Process {
Write-Host "Directory: " $dir
Write-Host "Days: "$days
}
Now call the script with your parameters.
.\modfilesTest.ps1 -dir c:\temp -days 7
A third alternative is to just paste a function definition into your console. At that point, the function is loaded into your current scope. Then you can just call the function.

Related

How to call a Scriptblock as a function parameter in Powershell

I would like to have a function to run different ScriptBlocks. So, I need to use my Scriptblock as the parameter of the function. It does not work.
For example. This function returns the ScriptBlock as a string.
function Run_Scriptblock($SB) {
return $SB
}
These are the outputs from my tries:
# 1st try
Run_Scriptblock {systeminfo}
>> systeminfo
# 2nd try
Run_Scriptblock systeminfo
>> systeminfo
# 3rd try
Run_Scriptblock [scriptblock]systeminfo
>> [scriptblock]systeminfo
# 4th try
$Command = [scriptblock]{systeminfo}
Run_Scriptblock $Command
>> [scriptblock]systeminfo
# 5th try
[scriptblock]$Command = {systeminfo}
Run_Scriptblock $Command
>> systeminfo
If you want a function to run a scriptblock, you need to actually invoke or call that scriptblock, i.e.
function Run_Scriptblock($SB) {
$SB.Invoke()
}
or
function Run_Scriptblock($SB) {
& $SB
}
Otherwise the function will just return the scriptblock definition in string form. The return keyword is not needed, since PowerShell functions return all non-captured output by default.
The function would be called like this:
Run_Scriptblock {systeminfo}
As a side note, I would recommend you consider naming your function following PowerShell conventions (<Verb>-<Noun> with an approved verb), e.g.
function Invoke-Scriptblock($SB) {
...
}

How to pass arguments to functions in PowerShell

I have the below PowerShell script
Function Publish
{
Param(
[parameter(Mandatory=$true)]
[String]
$RELEASEDIR,
[parameter(Mandatory=$true)]
[String]
$SERVICENAME,
[parameter(Mandatory=$true)]
[String]
$SERVER
)
Get-ChildItem "$RELEASEDIR\*"
$service = Get-Service -Name $SERVICENAME -Computername $SERVER -ErrorAction SilentlyContinue
$service.Status
}
Publish
How I am executing this:
PS C:\Release\RPCPS> .\RPCPublish.ps1 -RELEASEDIR "C:\Location" -SERVICENAME "value" -SERVER "server"
cmdlet Publish at command pipeline position 1
Supply values for the following parameters:
RELEASEDIR:
Even after passing arguments while executing, the script is expecting it again. What am I doing wrong here?
If you want to execute the script by calling the .ps1 as in your example, there is no need to use a function. Your script should look just like this:
Param(
[parameter(Mandatory=$true)]
[String]
$RELEASEDIR,
[parameter(Mandatory=$true)]
[String]
$SERVICENAME,
[parameter(Mandatory=$true)]
[String]
$SERVER
)
Get-ChildItem "$RELEASEDIR\*"
$service = Get-Service -Name $SERVICENAME -Computername $SERVER -ErrorAction SilentlyContinue
$service.Status
The parameters are passed directly to the script and can be used there.
If, on the other hand, you want to establish a (reusable) function, remove just the last line from your script, which calls the function without parameters (which is why it asks for the mandatory parameters every time).
If you remove the last line, you can call the script without parameters once. After that you have a new function Publish in your current session, which you can then call with
Publish -RELEASEDIR "C:\Release\Batchfile" -SERVICENAME "AmazonSSMAgent" -SERVER "10.0.1.91"
independent of the script file.
Your script is creating a function, "Publish", (lines 1-17) and then calling it with no parameters (line 18). Since you've defined parameters as mandatory (lines 4, 7, 10), failing to supply the parameters when you call the function (line 18) causes PowerShell to request values for the unsupplied parameters.
Supplying parameters to the script file itself does not help; there is no mechanism for "automagically" passing those parameters to anything within the script (you would have to explicitly code the script for that).
As Matt suggested in the comments, dot-source your script after deleting line 18, and then call your function explicitly, passing the parameters (publish -RELEASEDIR "C:\Release\Batchfile" -SERVICENAME "AmazonSSMAgent" -SERVER "10.0.1.91").
As per my understanding your requirement is to run the function, and you have to compile the scripts also in Jenkins.
You can do something like this:
Let's say your script name is RPCPublish.ps1 and the path is D:\Folder.
And I can see your function name is Publish.
So in your case,
powershell -command "& { D:\folder\RPCPublish.ps1; Publish }"
You can pass the parameters after this in the script block.
I used a PowerShell plugin (PowerShell) and executed the same.
. "C:\Release\RPCPS\RPCPublish.ps1"
FUunctionName -RELEASEDIR "C:\bin\Release" -SERVICENAME "Service" -SERVER "$env:SERVER" -DISPLAYNAME "Services Air" -BINPATH "D:\Build\Project.exe" -DESCRIPTION "This service hosts Air service" -DESTINATION "d$\Build\"

Correct Way To Request Parameters In Powershell

I'm trying to figure out the correct way to request parameters in a PowerShell script without using a function. With the following sample script I get an error if I don't include the Param within the function.
#Add SharePoint PowerShell SnapIn if not already added
if ((Get-PSSnapin "Microsoft.SharePoint.PowerShell" -ErrorAction SilentlyContinue) -eq $null) {
Add-PSSnapin "Microsoft.SharePoint.PowerShell"
}
function SomeFunctionName
{
Param(
[Parameter(Mandatory=$true)]
[string]$CollectionUrl,
[Parameter(Mandatory=$true)]
[string]$SourceList,
[Parameter(Mandatory=$true)]
[string]$DestList,
[Parameter(Mandatory=$true)]
[string]$ExpireDays
) # END PARAMS
#DO SOMETHING WITH THE PARAMETERS
}
If I remove the "function" and surrounding brackets just try to request parameters directly in the script I get the following error:
Missing closing ')' in expression.
You need to put the param(...) block at the top of the script before the If/Add-PSSnapin. You can have comments before the param but no other script.

Wrap existing powershell script as function?

I have a script like this:
[CmdletBinding()]
param(
[Parameter(Mandatory=$true)]
$Message
)
Write-Host "Hello, $Message!"
But I want to provide a method that allows users to dot source the script. Initially, I was just thinking I would wrap the whole script in a function to allow dot sourcing:
function Hello
{
[CmdletBinding()]
param(
[Parameter(Mandatory=$true)]
$Message
)
Write-Host "Hello, $Message!"
}
The problem with this is that if I did this, it would break the script for some people who are using it the old way. Is it possible to return an object with the same functionality as the script, or is there a way to dot source the script as it is (the first example above)?
I would suggest using splatting with $PSBoundParameters:
[CmdletBinding()]
param(
[Parameter(Mandatory=$true)]
$Message
)
function Hello
{
[CmdletBinding()]
param(
[Parameter(Mandatory=$true)]
$Message
)
Write-Host "Hello, $Message!"
}
Hello #PSBoundParameters
Alternatively: instead of dot-sourcing just create function from existing script:
$code = Get-Content .\HelloScript.ps1
New-Item -Path function:\Hello -Value ([scriptblock]::Create($code))
At the end of function Hello you must trigger it to simulate old behaviour. So if the script used to take an argument from command line, lets say c:\scripts\hello.ps1 bob, you can do it as so:
function Hello
{
...
}
if($args.Count -eq 0){
Hello $null
}
else{
Hello $args
}
$args will be an empty array if you were to run c:\scripts\newhello.ps1 without an argument, rather than $null as previously when no value was passed. Therefore we check $args.Count before triggering the function with correct parameter.
I know this is incredibly old but I just ran into it while doing something similar. I have a Foo.ps1 script that needs to work as a script but that I would also like available as one function exported from a module. It seems (I just started playing with it) as if putting the following (in Foo.psm1) function Foo { . "$PSScriptRoot\Foo.ps1" } works like a charm. Avoids having to write out all the arguments in two places.

PowerShell function return type not as expected

I have a script that accepts a string parameter :
script-that-takes-string-param.ps1
param(
[Parameter(Mandatory=$true, HelpMessage="path")]
[string]$path,
)
And I have another script that calls the first script :
parent-script.ps1
function CreateDir($dir) {
if (!(Test-Path $dir)) {
mkdir $dir
}
}
function CreatePath($BaseDir, $Environment, $Site, $Domain){
$path = [string]::format("{0}{1}\{2}\{3}", $BaseDir, $Environment, $Site, $Domain)
CreateDir $path
$path
}
$path = CreatePath 'c:\web\' 'qa' 'site1' 'com'
.\script-that-takes-string-param.ps1 -path $path
Running this script throws the exception :
"Cannot process argument transformation on parameter 'path'. Cannot convert value to type System.String"
Casting the parameter doesn't work :
.\script-that-takes-string-param.ps1 -path [string] $path
And casting the function result doesn't work either :
$path = [string] CreatePath 'global' 'site1'
But what is really strange is that if I run parent-script.ps1 twice from the PS command line, the 1st time it throws exceptions, but the 2nd time it executes with no errors.
My best guess would be that your
#do some other stuff with $path
writes something to the standard output, causing the function to return an array that contains said output and the path you expect. Can you send details on what you do in that bit?
Try removing "return". Output that is not saved to a variable is automatically returned. It shouldn't do any difference but it won't hurt to try.
Can you provide a full exception? Without seing the complete exception I get the feeling that the error is caused by something inside your script(ex. a function).
EDIT Your mkdir is causing the problem. When you run it, it returns an object representing the created directory(a DirectoryInfo object if I remember correctly). To fix this, try:
function CreateDir($dir) {
if (!(Test-Path $dir)) {
mkdir $dir | out-null
}
}
or combine them like:
function CreatePath($BaseDir, $Environment, $Site, $Domain){
$path = [string]::format("{0}{1}\{2}\{3}", $BaseDir, $Environment, $Site, $Domain)
if(!(Test-Path $path -PathType Container)) {
New-Item $path -ItemType Directory | Out-Null
}
$path
}