PowerShell Passing Variables - powershell

I am attempting to call a function in powershell, but pass it variables so I don't need to repeat the funxtion X amount of times with different values. I would like it so that, when I call the function I simply type:
Foo(Red,12,1.8)
And the generic function, foo, as follows:
function Foo(Colour, Age, Height){
<# Function does something with data here #>
}
Is this possible using powershell, and if so, would any changes made to those variables be saved after the function has completed?

Yes you can use parameters in functions.
By default the parameters only change within the scope of the function, but you can choose to return the same parameters as results if you like.
example (uses splatting)-
function Foo{
param(
[string]$Color,
[int]$Age,
[decimal]$Height
)
$Age += 1
$Height += 1
$ExampleOutput = [ordered]#{
Color = $Color
Age = $Age
Height = $Height
}
return ($ExampleOutput)
}
$Parameters = #{
Color = "Red"
Age = 12
Height = 1.8
}
Foo #Parameters

Yes try default values:
function Foo($Colour='Red',$Age=12,$Height=1.8){
<# Function does something with data here #>
}

Related

converting javascript "new RegExp" into powershell [regex]::new()

how would i implement the following javascript code snippet in powershell?
String.prototype.regexCount = function (pattern) {
if (pattern.flags.indexOf("g") < 0) {
pattern = new RegExp(pattern.source, pattern.flags + "g");
}
return (this.match(pattern) || []).length;
};
I'm thinking its something like this:
$regexCount = {
param(
$pattern
)
# ??????
if ($pattern.flags.indexOf("g") -lt 0) {
# ????
# $pattern = new RegExp(pattern.source, pattern.flags + "g");
$pattern = [regex]::new($pattern)
}
# ????
return ($this.match($pattern) || []).length;
}
I have almost the entire script converted into powershell except for this little nugget of code... Actually, i'm a little bit clueless when javascript starts creating lambda functions with regular expression objects...
for instance what's the significants of string.prototype.somename? wouldn't you just save the lambda to any variable name?
Using Update-TypeData, create a type-level ScriptMethod ETS member for the .NET string type (System.String):
Update-TypeData -TypeName System.String -MemberName RegexCount -MemberType ScriptMethod -Value {
param([regex] $Regex)
$Regex.Matches($this).Count
}
Now you can call the .RegexCount() method on any string instance, analogous to what your JavaScript code does.
Sample call:
'foo'.RegexCount('.') # -> 3
That is, 3 matches for regex . were found in the input string.

Accessing fixed size array elements from C# in PowerShell

Looking for a way to access individual array elements (continuation of this question)
$CSharpCode = #"
using System;
namespace TestStructure
{
public struct TestStructure
{
public byte Field1;
public unsafe fixed byte Field2[4];
}
}
"#
$cp = New-Object System.CodeDom.Compiler.CompilerParameters
$cp.CompilerOptions = '/unsafe'
Add-Type -TypeDefinition $CSharpCode -CompilerParameters $cp
function ConvertTo-Struct
{
# Only accept struct types (sealed value types that are neither primitive nor enum)
param(
[Parameter(Mandatory = $true)]
[ValidateScript({ $_.IsValueType -and $_.IsSealed -and -not($_.IsPrimitive -or $_.IsEnum) })]
[Type]$TargetType,
[Parameter(Mandatory = $true)]
[byte[]]$BinaryData
)
# Start by calculating minimum size of the underlying memory allocation for the new struct
$memSize = [System.Runtime.InteropServices.Marshal]::SizeOf([type]$TargetType)
# Make sure user actually passed enough data to initialize struct
if($memSize -gt $BinaryData.Length){
Write-Error "Not enough binary data to create an instance of [$($TargetType.FullName)]"
return
}
# now we just need some unmanaged memory in which to create our struct instance
$memPtr = [IntPtr]::Zero
try {
$memPtr = [System.Runtime.InteropServices.Marshal]::AllocHGlobal($memSize)
# copy byte array to allocated unmanaged memory from previous step
[System.Runtime.InteropServices.Marshal]::Copy($BinaryData, 0, $memPtr, $memSize)
# then marshal the new memory region as a struct and return
return [System.Runtime.InteropServices.Marshal]::PtrToStructure($memPtr, [type]$TargetType)
}
finally {
# and finally remember to clean up the allocated memory
if($memPtr -ne [IntPtr]::Zero){
[System.Runtime.InteropServices.Marshal]::FreeHGlobal($memPtr)
}
}
}
$testStructure = ConvertTo-Struct -TargetType ([TestStructure.TestStructure]) -BinaryData (1..100 -as [byte[]])
$testStructure.Field1
$testStructure.Field2
this produces the following output:
1
FixedElementField
-----------------
2
only the first array element of $Field2 is visible, can't access others using $testStructure.Field2[x]
Looking for a way to iterate over FixedBuffer of known type / size
$testStructure.Field2.GetType() says <Field2>e__FixedBuffer0
$testStructure.Field2.FixedElementField.GetType() is byte
can't see a way to access other elements of the array.
PowerShell's type adapter doesn't really have anything in place to handle unsafe fixed byte[] fields, effectively raw pointers from the underlying type system's point of view.
The declared size of the underlying memory allocation is only stored in metadata, which you can locate as follows:
# Locate appropriate field metadata
$fieldInfo = $testStructure.GetType().GetField('Field2')
# Discover fixed buffer attribute
$fixedBufferAttribute = $fieldInfo.CustomAttributes.Where({$_.AttributeType -eq [System.Runtime.CompilerServices.FixedBufferAttribute]}) |Select -First 1
Now we can figure out the size and which array element type is expected:
if($fixedBufferAttribute)
{
# Grab array element type + size from FixedBuffer attribute
$elemType,$size = $fixedBufferAttribute.ConstructorArguments
# Create array of appropriate size
$values = $elemType.MakeArrayType()::new($size)
# Copy values from fixed buffer pointer to managed array
try {
$fixedBufferHandle = [System.Runtime.InteropServices.GCHandle]::Alloc($TestStructure.Field2, 'Pinned')
[System.Runtime.InteropServices.Marshal]::Copy($fixedBufferHandle.AddrOfPinnedObject(), $values, 0, $size)
return $values
}
finally {
$fixedBufferHandle.Free()
}
}
You'll find $values now contains the expected byte values 2, 3, 4 and 5

How to let an event handler inside of a function modify a parameter passed by reference?

I'm using functions to create different WinForm elements; for example, RadioButtons inside of a GroupBox. I'm trying to pass in a variable representing the currently selected RadioButton that gets updated whenever a new one is selected.
function New-RadioButton
{
[OutputType([System.Windows.Forms.RadioButton])]
param
(
[int] $LocationX,
[int] $LocationY,
[string] $Label,
[System.Windows.Forms.RadioButton] $SelectedRB
)
$newButton = New-Object System.Windows.Forms.RadioButton
$newButton.Text = $Label
$newButton.AutoSize = $false
$newButton.Bounds = New-Object System.Drawing.Rectangle($LocationX, $LocationY, $RBWidth, $RBHeight)
$newButton.Add_CheckedChanged({
if($newButton.Checked) {
$SelectedRB = $newButton
}
}.GetNewClosure())
return $newButton
}
function New-GroupBox
{
[OutputType([System.Windows.Forms.GroupBox])]
param
(
[int] $LocationX,
[int] $LocationY,
[System.Windows.Forms.RadioButton] $SelectedRB
)
$rb1 = New-RadioButton $RBx $RB1y 'One' $SelectedRB
$rb2 = New-RadioButton $RBx $RB2y 'Two' $SelectedRB
$groupBox = New-Object System.Windows.Forms.GroupBox
$groupBox.AutoSize = $false
$groupBox.Bounds = New-Object System.Drawing.Rectangle($LocationX, $LocationY, $GBWidth, $GBHeight)
$groupBox.Controls.AddRange(#($rb1, $rb2))
return $groupBox
}
$Selection1 = New-Object System.Windows.Forms.RadioButton
$GroupBox1 = New-GroupBox $GB1x $GB1y $Selection1
$Selection2 = New-Object System.Windows.Forms.RadioButton
$GroupBox2 = New-GroupBox $GB2x $GB2y $Selection2
In specific, I'm using a script block inside of $newButton.Add_CheckChanged(), and trying to access the scope of the parent function to get and set the selection variable passed by reference. I'm not super proficient with PowerShell, I'm trying to write this like a lambda in C# and capture the scope of the parent. However, I know that this doesn't necessarily work in PowerShell - I've added {}.GetNewClosure(), but this only copies the current scope at creation time, not run-time.
I know that I could create script-wide variables (i.e. a script:$Selection or storing them in a hash table), but is there a solution that is agnostic to the name of the variable itself?
Edit: For reference, I'm using PowerShell 5.1.

How can I get the presentation details/rendering properties when using Find-Item command?

I want to get the renderings (presentation details) of each items.
I have tried using Get-Rendering, but it doesn't work.
$criteria = #(
#{ Filter = "Equals"; Field = "_template"; Value = "{9A43A639-4209-49B9-8024-766A9E1AB03E}"; },
#{ Filter = "DescendantOf"; Value = (Get-Item "master:/content/"); }
)
$props = #{
Index = "sitecore_master_index"
Criteria = $criteria
}
Find-Item #props | Get-Rendering -FinalLayout
It throws the following error:
The input object cannot be bound to any parameters for the command
either because the command does not take pipeline input or the input
and its properties do not match any of the parameters that take
pipeline input.
What am I missing?

Replace a variable as string with results from a subroutine in perl

I am trying to replace the variable "ex" with it's string value(which it gets from subroutine "potatoex()" and put it in the definition of another variable "goodge",
not getting any syntax error but this seems to be not working out.
Please help.
sub potatoex {
my $potato="Junos: 17.4DCB";
if($potato = ~/"Junos: 17.4[a-zA-Z0-9_.]*"/) {
print "/var/home/smoketest/dhcpv6.pl.28709.log";
}
}
main :
{
my $ex= potatoex();
my $goodge= "Apurva $ex Arnav";
print $goodge;
}
CURRENT O/P : /var/home/smoketest/dhcpv6.pl.28709.logApurva 1 Arnav
EXPECTED O/P: Apurva /var/home/smoketest/dhcpv6.pl.28709.log Arnav
Thanks,
Apurva
You are printing from your subroutine instead of returning the value from it. Try using return in potatoex.
sub potatoex {
my $potato = q{Junos: 17.4DCB};
my $returnVal = '';
if( $potato =~ /Junos: 17\.4[a-zA-Z0-9_.]*/ ) {
$returnVal = q{/var/home/smoketest/dhcpv6.pl.28709.log};
}
$returnVal;
}
{
my $ex = potatoex();
my $goodge = qq{Apurva $ex Arnav};
print $goodge;
}
While you could use return in an if block above (instead of print), I instead decided to use a variable, which will always return either the value you are trying to or an empty string. You could explicitly state the return return returnVal;, but it isn't required as perl allows implicit returns (make note of this and figure out if it should fit in your best practices or not).