Below is the code I’ve started to convert Scanstate.exe to a Powershell function. The problem I’m running in to right now is the interaction between a dynamic parameter and parameter sets.
function Invoke-ScanState {
[cmdletbinding(DefaultParameterSetName = 'StorePath')]
param(
[Parameter(ParameterSetName = 'StorePath',
Position = 0)]
[string] $StorePath = 'C:\Backup',
[Parameter(ParameterSetName = 'StorePath')]
[Parameter(ParameterSetName = 'Hardlink')]
[ValidateSet('Abort', 'Skip', 'DecryptCopy', 'CopyRaw', 'Hardlink')]
$Efs,
[Parameter(ParameterSetName = 'StorePath')]
[Parameter(ParameterSetName = 'Hardlink',
Mandatory)]
[switch] $NoCompress
)
dynamicParam {
if ($PSBoundParameters.ContainsValue('Hardlink')) {
$params = @{
'Name' = 'Hardlink'
'ParameterSetName' = 'Hardlink'
'Mandatory' = $true
'Type' = [switch]
}
New-DynamicParameter @params
}
}
begin {
$Hardlink = $PSBoundParameters.Hardlink
}
}
When I run the ‘Efs’ parameter with the ‘Hardlink’ value the ‘Hardlink’ switch dynamic parameter displays as expected as an option to choose in my function. What doesn’t work as expected is the ‘Hardlink’ switch parameter isn’t registering as a mandatory parameter. I can run ‘Invoke-ScanState -Efs Hardlink’ and it completes without requiring the ‘-Hardlink’ switch. Just to add to the confusion when I add the ‘-Hardlink’ switch the ‘NoCompress’ switch becomes mandatory, as expected. Hopefully this scenario makes sense. Are my parameter sets messed up somehow? I’m not sure what to do to actually make the ‘-Hardlink’ parameter mandatory when ‘-Efs Hardlink’ is specified.
I’ve included the ‘New-DynamicParameter’ function below. It’s the version from RamblingCookieMonster that I’ve modified slightly and added some things.
Function New-DynamicParameter {
[cmdletbinding()]
param(
[Parameter(Mandatory)]
[ValidateNotNullOrEmpty()]
[string] $Name,
[string[]] $ValidateSet,
[System.Type] $Type = [string],
[string[]] $Alias,
[switch] $Mandatory = $false,
[string] $ParameterSetName = "__AllParameterSets",
[switch] $ValueFromPipeline = $false,
[switch] $ValueFromPipelineByPropertyName = $false,
[string] $HelpMessage,
[int] $Position = $null,
[ValidateScript({
if (-not ($_ -is [System.Management.Automation.RuntimeDefinedParameterDictionary] -or -not $_)) {
Throw "DPDictionary must be a System.Management.Automation.RuntimeDefinedParameterDictionary object, or not exist"
}
$true
})]
$DPDictionary = $false
)
#Create attribute object, add attributes, add to collection
$ParamAttr = New-Object System.Management.Automation.ParameterAttribute
switch ($PSBoundParameters.Keys) {
'Mandatory' {$ParamAttr.Mandatory = $true}
'ValueFromPipeline' {$ParamAttr.ValueFromPipeline = $true}
'ValueFromPipelineByPropertyName' {$ParamAttr.ValueFromPipelineByPropertyName = $true}
'ParameterSetName' {$ParamAttr.ParameterSetName = $ParameterSetName}
'HelpMessage' {$ParamAttr.HelpMessage = $HelpMessage}
'Position' {$ParamAttr.Position = $Position}
}
$AttributeCollection = New-Object Collections.ObjectModel.Collection[System.Attribute]
$AttributeCollection.Add($ParamAttr)
#parameter validation set if specified
if ($PSBoundParameters.ContainsKey('ValidateSet')) {
$ParamOptions = New-Object System.Management.Automation.ValidateSetAttribute -ArgumentList $ValidateSet
$AttributeCollection.Add($ParamOptions)
}
#Aliases if specified
if ($PSBoundParameters.ContainsKey('Alias')) {
$ParamAlias = New-Object System.Management.Automation.AliasAttribute -ArgumentList $Alias
$AttributeCollection.Add($ParamAlias)
}
#Create the dynamic parameter
$Parameter = New-Object -TypeName System.Management.Automation.RuntimeDefinedParameter -ArgumentList @($Name, $Type, $AttributeCollection)
#Add the dynamic parameter to an existing dynamic parameter dictionary, or create the dictionary and add it
if ($PSBoundParameters.ContainsKey('DPDictionary')) {
$DPDictionary.Add($Name, $Parameter)
}
else {
$Dictionary = New-Object System.Management.Automation.RuntimeDefinedParameterDictionary
$Dictionary.Add($Name, $Parameter)
$Dictionary
}
}