Passing default values in powershell to another script - powershell

Given:
setenv.ps1:
param([Parameter(Mandatory=$false)][ValidateSet(541,642,643,644,645,"tmp")]$version=645)
echo "[setenv] Version = $version"
dbupdate.ps1:
param($version)
. setenv $version
echo "[dbupdate] Version = $version"
Output:
PS C:\> dbupdate.ps1
c:\utils\setenv.ps1 : Cannot validate argument on parameter 'version'. The argument is null, empty, or an element of the argument collection contains a null value. Supply a collection that does not
contain any null values and then try the command again.
At c:\utils\dbupdate.ps1:3 char:10
+ . setenv $version
+ ~~~~~~~~
+ CategoryInfo : InvalidData: (:) [setenv.ps1], ParameterBindingValidationException
+ FullyQualifiedErrorId : ParameterArgumentValidationError,setenv.ps1
[dbupdate] Version =
I want to invoke dbupdate.ps1 without any arguments, which should tell setenv.ps1 use the default value for the $version argument. However, the default value is the implementation detail of the serenv.ps1 script - I do not want it to "leak" into the dbupdate.ps1.
How do I do it?
EDIT
Trying to follow the advice of Cookie Monster yields the following error:
c:\dayforce\utils\setenv.ps1 : Cannot validate argument on parameter 'version'. The argument "System.Collections.Hashtable"
does not belong to the set "541,642,643,644,645,tmp" specified by the ValidateSet attribute. Supply an argument that is in the
set and then try the command again.
At C:\dayforce\utils\dbupdate.ps1:9 char:10
+ . setenv $params
+ ~~~~~~~
+ CategoryInfo : InvalidData: (:) [setenv.ps1], ParameterBindingValidationException
+ FullyQualifiedErrorId : ParameterArgumentValidationError,setenv.ps1

This is a good use case for splatting your arguments. Particularly if you ever need to do it for more than a single parameter...
Modified dbupdate.ps1:
param($version)
#Build a hashtable containing the parameters and values you want to call
$params = #{}
if($version) { $params.version = $version }
. setenv #params
You could even use #PSBoundParameters, there's an example of this in the help system. Run Get-Help about_Splatting for more information!
Edit for clarification
Not sure why this was downvoted. Here is verification that this syntax works. Calling #params is required, not $params.
Lastly, here is one more example demonstrating splatting PSBoundParameters, even less code:
Get-Help about_Splatting or Googling "PowerShell splatting" will provide more examples if needed!

Your overriding the default value with a value of null. The validateset attribute seems to be causing that error. I tried adding allownull,allowemptystring and allowemptycollection and added a null value to the set but validateset still caused that error. As an alternative you could just do this -
if ($version) {
. .\setenv.ps1 $version
} else {
. .\setenv.ps1
}

Related

Azure Pipeline: Pass System.Debug to a pwsh switch parameter

How do I parse a variable which is either the string "True" or non-existent into a boolean?
I'm trying to pass the value of the predefined azure pipeline variable "system.debug" into a pwsh script as the argument to a switch parameter. I've tried both of these approaches:
-isDebug:([boolean]'$(System.Debug)')
-isDebug:$$(System.Debug)
Both of these approaches work when the "Enable system diagnostics" option is checked. It gets a value of "True" which I then must parse. However, if not checked the System.Debug variable doesn't exist at all, not false or null. This makes my parse fail below:
$isDebug = $false
if($$(System.Debug)){
$isDebug = $$(System.Debug)
}
Error:
+ $isDebug = $$(System.Debug)
+ ~
Unexpected token '(' in expression or statement.
+ CategoryInfo : ParserError: (:) [], ParentContainsErrorRecordException
+ FullyQualifiedErrorId : UnexpectedToken
I was able to check if the environment variable exists with get-environmentVariable and if it does use the value, otherwise don't pass the switch parameter at all.
if([Environment]::GetEnvironmentVariable('SYSTEM_DEBUG') -ne $null){
write-host "SYSTEM_DEBUG: $(system.debug)"
./myscript.ps1 -isDebug:([boolean]$($env:SYSTEM_DEBUG))
}
else {
write-host "SYSTEM_DEBUG was not set"
./myscript.ps1
}

How to set environment variable with dot in name using powershell?

I want to set environment variable in powershell that has dot in name.
This line throws an error:
$env:Test.Env.Var1 = "test111"
The property 'Var1' cannot be found on this object. Verify that the property exists and can be set.
At line:1 char:1
+ $env:Test.Env.Var1 = "test111"
+ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ CategoryInfo : InvalidOperation: (:) [], RuntimeException
+ FullyQualifiedErrorId : PropertyNotFound
Is it possible to set "Test.Env.Var1" variable without using [Environment]::SetEnvironmentVariable method?
This can be done by
${env:test.value} = 'value'
Note the colon after env. This works in both powershell and pwsh
Cf. https://learn.microsoft.com/en-us/powershell/module/microsoft.powershell.core/about/about_variables?view=powershell-7.2#variable-names-that-include-special-characters
It can be done by
${env:Test.Env.Var1} = 'value'
source
Thanks to #4c74356b41 who provided answer in comment.

PowerShell error 'can't call null-value expresssion' [duplicate]

I am simply trying to create a powershell script which calculates the md5 sum of an executable (a file).
My .ps1 script:
$answer = Read-Host "File name and extension (ie; file.exe)"
$someFilePath = "C:\Users\xxx\Downloads\$answer"
If (Test-Path $someFilePath){
$stream = [System.IO.File]::Open("$someFilePath",[System.IO.Filemode]::Open, [System.IO.FileAccess]::Read)
$hash = [System.BitConverter]::ToString($md5.ComputeHash($stream))
$hash
$stream.Close()
}
Else{
Write-Host "Sorry, file $answer doesn't seem to exist."
}
Upon running my script I receive the following error:
You cannot call a method on a null-valued expression.
At C:\Users\xxx\Downloads\md5sum.ps1:6 char:29
+ $hash = [System.BitConverter]::ToString($md5.Compute ...
+ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ CategoryInfo : InvalidOperation: (:) [], RuntimeException
+ FullyQualifiedErrorId : InvokeMethodOnNull
To my understanding, this error means the script is attempting to do something, but another part of the script does not have any information to permit the first part of the script to work properly. In this case, $hash.
Get-ExecutionPolicy outputs Unrestricted.
What is causing this error?
What exactly is my null valued expression?
Any help is appreciated. I apologize if this is trivial and will continue my research.
References:
http://blogs.technet.com/b/heyscriptingguy/archive/2013/03/27/troubleshoot-the-invokemethodonnull-error-with-powershell.aspx
How to get an MD5 checksum in PowerShell
The simple answer for this one is that you have an undeclared (null) variable. In this case it is $md5. From the comment you put this needed to be declared elsewhere in your code
$md5 = new-object -TypeName System.Security.Cryptography.MD5CryptoServiceProvider
The error was because you are trying to execute a method that does not exist.
PS C:\Users\Matt> $md5 | gm
TypeName: System.Security.Cryptography.MD5CryptoServiceProvider
Name MemberType Definition
---- ---------- ----------
Clear Method void Clear()
ComputeHash Method byte[] ComputeHash(System.IO.Stream inputStream), byte[] ComputeHash(byte[] buffer), byte[] ComputeHash(byte[] buffer, int offset, ...
The .ComputeHash() of $md5.ComputeHash() was the null valued expression. Typing in gibberish would create the same effect.
PS C:\Users\Matt> $bagel.MakeMeABagel()
You cannot call a method on a null-valued expression.
At line:1 char:1
+ $bagel.MakeMeABagel()
+ ~~~~~~~~~~~~~~~~~~~~~
+ CategoryInfo : InvalidOperation: (:) [], RuntimeException
+ FullyQualifiedErrorId : InvokeMethodOnNull
PowerShell by default allows this to happen as defined its StrictMode
When Set-StrictMode is off, uninitialized variables (Version 1) are assumed to have a value of 0 (zero) or $Null, depending on type. References to non-existent properties return $Null, and the results of function syntax that is not valid vary with the error. Unnamed variables are not permitted.

How to pass a custom enum to a function in powershell

When defining a function, how can you reference a custom enum?
Here's what I'm trying:
Add-Type -TypeDefinition #"
namespace JB
{
public enum InternetZones
{
Computer
,LocalIntranet
,TrustedSites
,Internet
,RestrictedSites
}
}
"# -Language CSharpVersion3
function Get-InternetZoneLogonMode
{
[CmdletBinding()]
param
(
[Parameter(Mandatory=$true)]
[JB.InterfaceZones]$zone
)
[string]$regpath = ("HKCU\Software\Microsoft\Windows\CurrentVersion\Internet Settings\Zones\{0}" -f [int]$zone)
$regpath
#...
#Get-PropertyValue
}
Get-InternetZoneLogonMode -zone [JB.InternetZones]::TrustedSites
But this gives the error:
Get-ZoneLogonMode : Unable to find type [JB.InterfaceZones]. Make sure that the assembly that contains this type is loaded.
At line:29 char:1
+ Get-ZoneLogonMode -zone [JB.InternetZones]::TrustedSites
+ ~~~~~~~~~~~~~~~~~
+ CategoryInfo : InvalidOperation: (JB.InterfaceZones:TypeName) [], RuntimeException
+ FullyQualifiedErrorId : TypeNotFound
NB: I'm aware I could use ValidateSet for similar functionality; however that has the disadvantage of only having a name value; as opposed to allowing me to program using friendly names which are then mapped to ints in the background (I could write code for that; but enum seems more appropriate if possible).
I'm using Powershell v4, but ideally I'd like a PowerShell v2 compatible solution as most users are on that version by default.
Update
I've corrected the typo (thanks PetSerAl; well spotted).
[JB.InterfaceZones]$zone now changed to [JB.InternetZones]$zone.
Now I'm seeing error:
Get-InternetZoneLogonMode : Cannot process argument transformation on parameter 'zone'. Cannot convert value "[JB.InternetZones]::TrustedSites" to type
"JB.InternetZones". Error: "Unable to match the identifier name [JB.InternetZones]::TrustedSites to a valid enumerator name. Specify one of the following
enumerator names and try again: Computer, LocalIntranet, TrustedSites, Internet, RestrictedSites"
At line:80 char:33
+ Get-InternetZoneLogonMode -zone [JB.InternetZones]::TrustedSites
+ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ CategoryInfo : InvalidData: (:) [Get-InternetZoneLogonMode], ParameterBindingArgumentTransformationException
+ FullyQualifiedErrorId : ParameterArgumentTransformationError,Get-InternetZoneLogonMode
The ISE gave this one away to me but your attempted syntax was not completely incorrect. I was able to do this and get it to work.
Get-InternetZoneLogonMode -Zone ([JB.InternetZones]::TrustedSites)
Again, If you look at the highlighting you will see how I came to that conclusion.
Per comments by PetSerAl & CB:
Corrected typo in function definition
from [JB.InterfaceZones]$zone
to [JB.InternetZones]$zone
Changed function call
from Get-InternetZoneLogonMode -zone [JB.InternetZones]::TrustedSites
to Get-InternetZoneLogonMode -zone TrustedSites

powershell function parameter types

have the following function:
function appendToSB([System.Text.StringBuilder]$sb,
[string]$value){
[void]$sb.append($value)
$sb
}
$sb = new-object -typename system.text.stringbuilder
$sb = appendToSb($sb, "1,")
$sb.tostring() | out-host
i want to build string using StringBuilder using my function for that, but i receive the following error:
appendToSB : Cannot process argument transformation on parameter 'sb'.
Cannot convert the "System.Object[]" value of ty pe "System.Object[]"
to type "System.Text.StringBuilder". At E:\powershell\test.ps1:8
char:11
+ appendToSb([system.text.stringbuilder]$sb, "1,")
+ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ CategoryInfo : InvalidData: (:) [appendToSB], ParameterBindingArgumentTransformationException
+ FullyQualifiedErrorId : ParameterArgumentTransformationError,appendToSB
does anybody can explain how function/function parameter/return values works in powershell?
Classic PowerShell issue. You don't use parens or comma separated args when calling commands or functions e.g.:
appendToSb $sb "1,"
You only use that syntax when calling .NET methods. If you use Set-StrictMode -Version 2 it will catch this sort of issue. What you passed ($sb, "1,") is how you would pass an array to a single parameter. Technically the parens aren't needed but don't change the value i.e. you could pass an array like this as well $sb, ",".