I'm writing a powershell script which uses write-host to output another powershell script. How can I write out a boolean parameter with the value $true (or $false) including the dollar sign:
param
(
[switch] $myParam = $true
)
Write-Host My Param is $myParam
I need this to output exactly
My Param is $True
But it outputs
My Param is True
You can escape a $ with a `:
Write-Host My Param is `$$myParam
This would achieve what I think you want:
Write-Host My Param is `$$myParam
Related
This is the content of the my_script.ps1 file:
function InitDotnet {
param (
[Parameter(Mandatory)]
[string]
$ProjectName,
[Parameter(Mandatory)]
[ValidateSet("cli", "lib")]
[string]
$ProjectType,
[Parameter]
[bool]
$Xunit = $false,
[Parameter]
[bool]
$Src = $false
)
Write-Host "Name:" $ProjectName
Write-Host "Type:" $ProjectType
Write-Host "Create a xunit project:" $Xunit
Write-Host "Create a src folder:" $Src
}
InitDotnet $args[0] $args[1] $args[2] $args[3]
First, I don't know why the default bool values don't work.
.\my_script.ps1 Test lib
Name: Test
Type: lib
Needs xUnit:
Create a src folder:
And I can't pass Boolean arguments to my .ps1 script without casting errors.
.\my_script.ps1 Test lib $true
InitDotnet : Cannot process argument transformation on parameter 'Xunit'.
Cannot convert value "True" to type "System.Management.Automation.ParameterAttribute".
Error: "Invalid cast from 'System.Boolean' to 'System.Management.Automation.ParameterAttribute'."
What am I doing wrong?
I am attempting to use ValidateSet with a boolean parameter however I cannot get it to function as expect.
An example to replicate the issue:
function Set-Boolean
{
[CmdletBinding()]
[OutputType([Bool])]
Param
(
[Parameter(Mandatory=$true, Position=0)]
[ValidateNotNullOrEmpty()]
[ValidateSet($false,$true)]
[Bool] $Bool
)
Process
{
$Bool
}
}
At run time PowerShell expands the $true and $false variables upon tab completion to True and False respectively however this then cause the parameter validation to fail as only $true, $false, 1 and 0 are valid boolean types.
I tried changing ValidateSet to [ValidateSet('$false','$true')] and the tab completion works as expected however the parameter validation still fails as the parameter is expecting the strings '$false' and '$true'.
I could change ValidateSet to [ValidateSet([bool]0,[bool]1)] and have it function as I expect but I find 0 and 1 a poorer user experience over $true and $false for completion of a boolean parameter.
The expected output of the function should be True when $true is chosen and False when $false is chosen.
I have implemented a workaround in my code but I want to know how I can use ValidateSet with a boolean parameter, if it is possible, to enable the use of tab completion for the user.
Joining some answers, the best option will depend on the needs, if the parameter is type boolean it can be replaced by one of type switch, but if you want to specify the value to see in the code or by style; It can be done as follows.
function Write-SwitchParam {
[CmdletBinding()]
param (
[Switch] #[Switch] or [System.Management.Automation.SwitchParameter]
$SwitchParam
)
if($SwitchParam)
{
Write-Host "Switch is present. Do Positive Action."
}
else {
Write-Host "Switch isn't present. Do Negative Action."
}
}
function Write-BooleanParam {
[CmdletBinding()]
Param(
[parameter(Position=0, ValueFromPipeline=$true)]
[ValidateNotNullOrEmpty()]
[ValidateSet($true, $false, 0, 1)]
$BoolParam = $true
)
Begin{
}
Process{
$value = [System.Convert]::ToBoolean($BoolParam)
Write-Host $value
}
End{
}
}
Write-Host "TESTS BOOLEAN PARAM" -ForegroundColor Magenta
Write-BooleanParam -BoolParam $true
Write-BooleanParam -BoolParam $false
Write-Host
Write-BooleanParam $false
Write-BooleanParam $true
Write-Host
Write-BooleanParam True
Write-BooleanParam False
Write-Host
Write-BooleanParam 0
Write-BooleanParam 1
Write-Host
Write-BooleanParam
Write-Host
$true, $false, "True", "False", 1, 0 | Write-BooleanParam
Write-Host
Write-Host "TESTS SWITCH PARAM" -ForegroundColor Magenta
Write-SwitchParam
Write-SwitchParam -SwitchParam
You can use ValidateSet for autocompletion without specifying the input variable type. Though, you cannot use 0 and 1 as input in this case:
function Set-Boolean
{
[CmdletBinding()]
[OutputType([Bool])]
Param
(
[Parameter(Mandatory=$true, Position=0)]
[ValidateNotNullOrEmpty()]
[ValidateSet($false,$true)]
$Bool
)
Process
{
[System.Convert]::ToBoolean($Bool)
}
}
This gives the tab completion for the user, as desired using ValidateSet, but is achieved by registering an argument completer instead (especially in the ISE);
function Set-Boolean
{
[CmdletBinding()]
[OutputType([Bool])]
Param
(
[Parameter(Mandatory=$true, Position=0)]
[ValidateNotNullOrEmpty()]
[Bool] $Bool
)
Process
{
$Bool
}
}
Register-ArgumentCompleter -CommandName 'Set-Boolean' -ParameterName 'Bool' -ScriptBlock {
[System.Management.Automation.CompletionResult]::new(
'$False',
'$False',
'ParameterValue',
'[bool] False'
)
[System.Management.Automation.CompletionResult]::new(
'$True',
'$True',
'ParameterValue',
'[bool] True'
)
}
Consider the following code:
function Test
{
[CmdletBinding()]
param
(
[parameter(Mandatory=$true)]
[AllowNull()]
[String]
$ComputerName
)
process{}
}
Test -ComputerName $null
Based on the official documentation for AllowNull I was expecting that $ComputerName could either be [string] or $null. However, running the above code results in the following error:
[14,24: Test] Cannot bind argument to parameter 'ComputerName' because it is an empty
string.
Why doesn't passing $null for $ComputerName work in this case?
$null, when converted to [string], return empty string not $null:
[string]$null -eq $null # False
[string]$null -eq [string]::Empty # True
If you want to pass $null for [string] parameter you should use [NullString]::Value:
[string][NullString]::Value -eq $null # True
Test -ComputerName ([NullString]::Value)
You also need to add the [AllowEmptyString()] attribute if you plan on allowing nulls and empty strings.
function Test
{
[CmdletBinding()]
param
(
[parameter(Mandatory=$true)]
[AllowNull()]
[AllowEmptyString()]
[String]
$ComputerName
)
process{}
}
Test -ComputerName $null
As noted, when cast to a [string], $null becomes an empty string (""). To avoid this, one option is to type the param as an object - then in the body test first for $null, then check that $MyParam.GetType().Name is "String".
I'm trying to get my powershell script to prompt for input, but still use a dynamicparam. If I pass the parameters through the command line (Example: DeployBuild "DEV02" "ClientPortal" "a" "b") , then the below code works fine, and I get prompted for the dynamic param. If I chose not to pass the parameters via command line (Example: DeployBuild), and instead let the script prompt for input, the dynamic parameter quits working. Does anyone have an idea why this is not working?
Function DeployBuild {
[CmdletBinding()]
Param
(
[ValidateSet("DEV01","DEV02","PEDEV01","QA01","QA02","UAT","PERF01","PROD")]
[Parameter(Mandatory=$true, Position=1)]
[String]$environment,
[Parameter(Mandatory=$true, Position=2)]
[ValidateSet("AuthenticationService","ClientPortal")]
[String]$application,
[Parameter(Mandatory=$true, Position=3)]
[String]$buildName,
[Parameter(Mandatory=$true, Position=4)]
[String]$buildNumber
)
DynamicParam{
if ($environment -eq "DEV02"){
#create a new ParameterAttribute Object
$buildVersionAttribute = New-Object System.Management.Automation.ParameterAttribute
$buildVersionAttribute.Position = 5
$buildVersionAttribute.Mandatory = $true
#create an attributecollection object for the attribute just created.
$attributeCollection = new-object System.Collections.ObjectModel.Collection[System.Attribute]
#add our custom attribute
$attributeCollection.Add($buildVersionAttribute)
#add our paramater specifying the attribute collection
$buildVersionParam = New-Object System.Management.Automation.RuntimeDefinedParameter('buildVersion', [double], $attributeCollection)
#expose the name of our parameter
$paramDictionary = New-Object System.Management.Automation.RuntimeDefinedParameterDictionary
$paramDictionary.Add('buildVersion', $buildVersionParam)
return $paramDictionary
}
}
End{
Write-Host $environment
Write-Host $application
Write-Host $buildName
Write-Host $buildNumber
Write-Host $PSBoundParameters.buildVersion
}
}
Well this is really old so you probably don't need it anymore, but I'm pretty sure the reason this is happening is because of the conditional in the DynamicParam block that looks to see what the value of $environment is.
When the DynamicParam block is evaluated, $environment is blank, so the parameter is never added.
You can demonstrate this for yourself like this:
DynamicParam {
Write-Verbose "DynamicParam here, environment is: '$environment'" -Verbose
# ... rest of code here
}
Now run DeployBuild with no parameters and you'll see exactly when the block is being evaluated.
I have a simple code that accepts two parameters. The parameters are optional. Below is the code.
[CmdletBinding()]
Param(
[Parameter(Mandatory=$False)]
[string]$pA,
[Parameter(Mandatory=$False)]
[string]$pB
)
when running the script I want to know which parameter is passed. pA or pB.
$MyInvocation.BoundParameters
return a ps custom dictionary pair (key/value) with all passed parameter.
this is the content of a.ps1 file:
[CmdletBinding()]
Param(
[Parameter(Mandatory=$False)]
[string]$pA,
[Parameter(Mandatory=$False)]
[string]$pB
)
$MyInvocation.BoundParameters
running this script gives:
PS C:\ps> a -pA pAparam
Key Value
--- -----
pA pAparam
then you can check what key is present:
[bool]($MyInvocation.BoundParameters.Keys -match 'pa') # or -match 'pb' belong your needs
As you cas $Pa and $Pb you can test if they are empty:
You can test with this function :
function func
{
[CmdletBinding()]
Param([Parameter(Mandatory=$False)]
[string]$pA,
[Parameter(Mandatory=$False)]
[string]$pB
)
if ($pA -eq [string]::Empty -and $pA -eq [string]::Empty)
{
Write-Host "Both are empty"
}
elseif ($pA -ne [string]::Empty)
{
Write-Host "Pa is not empty"
}
elseif ($pB -ne [string]::Empty)
{
Write-Host "Pb is not empty"
}
}
Clear-Host
func
Remains the problem that func -Pa "" will give same results as func But if you just want to test the presence of a parameter you can use the switch attribute.
You can find more about PowerShell scripts and function parameters with these links:
about_Functions
about_Functions_Advanced
about_Functions_Advanced_Parameters