สร้างโค้ดพารามิเตอร์ไดนามิกของ PowerShell
หนึ่งในหัวข้อที่เราได้พูดคุยกันในคณะทำงาน PowerShell Cmdlet คือคำขอเพื่อให้แทรกพารามิเตอร์แบบไดนามิกได้ง่ายขึ้น ฉันขาดเรื่องนี้เล็กน้อย ในด้านหนึ่ง ฉันเห็นค่าในพารามิเตอร์ไดนามิก พารามิเตอร์เหล่านี้เป็นพารามิเตอร์ที่มีอยู่เฉพาะในกรณีที่ตรงตามเงื่อนไขบางประการ เช่น ตำแหน่งปัจจุบันอยู่ในรีจิสทรีของ Windows ข้อเสียคือพารามิเตอร์เหล่านี้ค้นพบได้ยากและยุ่งยากในการจัดทำเอกสาร ยิ่งไปกว่านั้น โค้ด PowerShell ที่จำเป็นในการกำหนดพารามิเตอร์ไดนามิกยังมีความซับซ้อนและไม่ใช่ระดับเริ่มต้นอย่างแน่นอน นี่คือสิ่งที่ฉันคิดว่าปัญหานี้เป็นเรื่องเกี่ยวกับจริงๆ ดังนั้นฉันจึงตัดสินใจเขียนเครื่องมือของตัวเองเพื่อให้แทรกพารามิเตอร์ไดนามิกได้ง่ายขึ้น
การกำหนดความต้องการ
ขั้นตอนแรกคือการตัดสินใจว่าเหตุใดคุณจึงต้องใช้พารามิเตอร์แบบไดนามิก หลายครั้ง ฉันคิดว่าชุดพารามิเตอร์อาจช่วยแก้ปัญหาได้ แต่สมมติว่าคุณต้องการพารามิเตอร์ตามเงื่อนไขบางประการ นี่คือตัวอย่าง นี่คือฟังก์ชันสาธิตที่แสดงการใช้งานไดรฟ์โดยใช้ Out-Gridview
Function Get-DriveGridView {
[cmdletbinding(DefaultParameterSetName = "computer")]
[OutputType("none","object")]
Param(
[parameter(Position = 0, ValueFromPipeline, ParameterSetName = "computer")]
[ValidateNotNullOrEmpty()]
[string]$Computername = $env:COMPUTERNAME,
[parameter(ValueFromPipeline, ParameterSetName = "session")]
[ValidateNotNullOrEmpty()]
[Microsoft.Management.Infrastructure.CimSession]$CimSession,
[Parameter(HelpMessage = "Enter a title to use for the GridView")]
[ValidateNotNullOrEmpty()]
[string]$Title = "Drive Report",
[Parameter(HelpMessage = "pass results to the pipeline in addition to the grid view")]
[switch]$Passthru
)
Begin {
Write-Verbose "[$((Get-Date).TimeofDay) BEGIN ] Starting $($myinvocation.mycommand)"
Write-Verbose "[$((Get-Date).TimeofDay) BEGIN ] Collecting drive information...please wait"
#initialize a list to hold the results
$results = [System.Collections.Generic.list[object]]::new()
#hashtable of Get-CimInstance parameters for splatting
$splat = @{
Classname = "win32_logicaldisk"
Filter = "drivetype=3"
ErrorAction = "Stop"
Property = "SystemName", "DeviceID", "Size", "Freespace"
}
} #begin
Process {
If ($pscmdlet.ParameterSetName -eq 'computer') {
Write-Verbose "[$((Get-Date).TimeofDay) PROCESS] Getting data from computer $($computername.toUpper())"
$splat["Computername"] = $Computername
$remote = $Computername.ToUpper()
}
else {
Write-Verbose "[$((Get-Date).TimeofDay) PROCESS] Getting data from cimsession $($cimsession.computername.toUpper())"
$splat["CimSession"] = $cimSession
$remote = $cimSession.computername.toUpper()
}
Try {
Get-CimInstance @splat | Select-Object -Property @{Name = "Computername"; Expression = { $_.Systemname } },
@{Name = "Drive"; Expression = { $_.DeviceID } },
@{Name = "SizeGB"; Expression = { [int]($_.Size / 1GB) } },
@{Name = "FreeGB"; Expression = { [int]($_.Freespace / 1GB) } },
@{Name = "UsedGB"; Expression = { [math]::round(($_.size - $_.Freespace) / 1GB, 2) } },
@{Name = "Free%"; Expression = { [math]::round(($_.Freespace / $_.Size) * 100, 2) } },
@{Name = "FreeGraph"; Expression = {
[int]$per = (($_.Freespace / $_.Size) * 100/2)
"|" * $per }
} | ForEach-Object { $results.Add($_) }
} #try
Catch {
Write-Warning "Failed to get drive data from $remote. $($_.exception.message)"
}
} #process
End {
#send the results to Out-Gridview
Write-Verbose "[$((Get-Date).TimeofDay) END ] Found $($results.count) total items"
if ($results.count -gt 1) {
$Results | Sort-Object -Property Computername | Out-GridView -Title $Title
if ($passthru) {
$results
}
}
else {
Write-Warning "No drive data found to report."
}
Write-Verbose "[$((Get-Date).TimeofDay) END ] Ending $($myinvocation.mycommand)"
} #end
}มันใช้งานได้ดี
แต่ PowerShell 7 มีคำสั่งใหม่ที่เรียกว่า Out-ConsoleGridView ติดตั้งโมดูล Microsoft.PowerShell.ConsoleGuiTools จาก PowerShell Gallery เพื่อรับคำสั่งนี้ ฉันต้องการรวมพารามิเตอร์แบบไดนามิกเพื่อใช้คำสั่งนี้แทน Out-Gridview หากมี ซึ่งหมายความว่าฉันจะต้องเขียนโค้ด PowerShell เพื่อกำหนดพารามิเตอร์นี้
[cmdletbinding(DefaultParameterSetName = "computer")]
[OutputType("none","object")]
Param(
[parameter(Position = 0, ValueFromPipeline, ParameterSetName = "computer")]
[ValidateNotNullOrEmpty()]
[string]$Computername = $env:COMPUTERNAME,
[parameter(ValueFromPipeline, ParameterSetName = "session")]
[ValidateNotNullOrEmpty()]
[Microsoft.Management.Infrastructure.CimSession]$CimSession,
[Parameter(HelpMessage = "Enter a title to use for the GridView")]
[ValidateNotNullOrEmpty()]
[string]$Title = "Drive Report",
[Parameter(HelpMessage = "pass results to the pipeline in addition to the grid view")]
[switch]$Passthru
)
DynamicParam {
#offer to use Out-ConsoleGridView if installed in PowerShell 7
...นี่เป็นส่วนที่น่าเบื่อ
ใหม่-PSDynamicParameter
แต่ฉันจะใช้ฟังก์ชันนี้เพื่อสร้างโค้ด PowerShell โดยอัตโนมัติ
Function New-PSDynamicParameter {
<#
.Synopsis
Create a PowerShell dynamic parameter
.Description
This command will create the code for a dynamic parameter that you can insert into your PowerShell script file.
.Link
about_Functions_Advanced_Parameters
#>
[cmdletbinding()]
[alias("ndp")]
[outputtype([System.String[]])]
Param(
[Parameter(Position = 0, Mandatory, HelpMessage = "Enter the name of your dynamic parameter.`nThis is a required value.")]
[ValidateNotNullOrEmpty()]
[alias("Name")]
[string[]]$ParameterName,
[Parameter(Mandatory, HelpMessage = "Enter an expression that evaluates to True or False.`nThis is code that will go inside an IF statement.`nIf using variables, wrap this in single quotes.`nYou can also enter a placeholder like '`$True' and edit it later.`nThis is a required value.")]
[ValidateNotNullOrEmpty()]
[string]$Condition,
[Parameter(HelpMessage = "Is this dynamic parameter mandatory?")]
[switch]$Mandatory,
[Parameter(HelpMessage = "Enter an optional default value.")]
[object[]]$DefaultValue,
[Parameter(HelpMessage = "Enter an optional parameter alias.`nSpecify multiple aliases separated by commas.")]
[string[]]$Alias,
[Parameter(HelpMessage = "Enter the parameter value type such as String or Int32.`nUse a value like string[] to indicate an array.")]
[type]$ParameterType = "string",
[Parameter(HelpMessage = "Enter an optional help message.")]
[ValidateNotNullOrEmpty()]
[string]$HelpMessage,
[Parameter(HelpMessage = "Does this dynamic parameter take pipeline input by property name?")]
[switch]$ValueFromPipelineByPropertyName,
[Parameter(HelpMessage = "Enter an optional parameter set name.")]
[ValidateNotNullOrEmpty()]
[string]$ParameterSetName,
[Parameter(HelpMessage = "Enter an optional comment for your dynamic parameter.`nIt will be inserted into your code as a comment.")]
[ValidateNotNullOrEmpty()]
[string]$Comment,
[Parameter(HelpMessage = "Validate that the parameter is not NULL or empty.")]
[switch]$ValidateNotNullOrEmpty,
[Parameter(HelpMessage = "Enter a minimum and maximum string length for this parameter value`nas an array of comma-separated set values.")]
[ValidateNotNullOrEmpty()]
[int[]]$ValidateLength,
[Parameter(HelpMessage = "Enter a set of parameter validations values")]
[ValidateNotNullOrEmpty()]
[object[]]$ValidateSet,
[Parameter(HelpMessage = "Enter a set of parameter range validations values as a`ncomma-separated list from minimum to maximum")]
[ValidateNotNullOrEmpty()]
[int[]]$ValidateRange,
[Parameter(HelpMessage = "Enter a set of parameter count validations values as a`ncomma-separated list from minimum to maximum")]
[ValidateNotNullOrEmpty()]
[int[]]$ValidateCount,
[Parameter(HelpMessage = "Enter a parameter validation regular expression pattern")]
[ValidateNotNullOrEmpty()]
[string]$ValidatePattern,
[Parameter(HelpMessage = "Enter a parameter validation scriptblock.`nIf using the form, enter the scriptblock text.")]
[ValidateNotNullOrEmpty()]
[scriptblock]$ValidateScript
)
Begin {
Write-Verbose "[$((Get-Date).TimeofDay) BEGIN ] Starting $($myinvocation.mycommand)"
$out = @"
DynamicParam {
$(If ($comment) { "$([char]35) $comment"})
If ($Condition) {
`$paramDictionary = New-Object -Type System.Management.Automation.RuntimeDefinedParameterDictionary
"@
} #begin
Process {
if (-Not $($PSBoundParameters.ContainsKey("ParameterSetName"))) {
$PSBoundParameters.Add("ParameterSetName", "__AllParameterSets")
}
#get validation tests
$Validations = $PSBoundParameters.GetEnumerator().Where({ $_.key -match "^Validate" })
#this is structured for future development where you might need to create
#multiple dynamic parameters. This feature is incomplete at this time
Foreach ($Name in $ParameterName) {
Write-Verbose "[$((Get-Date).TimeofDay) PROCESS] Defining dynamic parameter $Name [$($parametertype.name)]"
$out += "`n # Defining parameter attributes`n"
$out += " `$attributeCollection = New-Object -Type System.Collections.ObjectModel.Collection[System.Attribute]`n"
$out += " `$attributes = New-Object System.Management.Automation.ParameterAttribute`n"
#add attributes
$attributeProperties = 'ParameterSetName', 'Mandatory', 'ValueFromPipeline', 'ValueFromPipelineByPropertyName', 'ValueFromRemainingArguments', 'HelpMessage'
foreach ($item in $attributeProperties) {
if ($PSBoundParameters.ContainsKey($item)) {
Write-Verbose "[$((Get-Date).TimeofDay) PROCESS] Defining $item"
if ( $PSBoundParameters[$item] -is [string]) {
$value = "'$($PSBoundParameters[$item])'"
}
else {
$value = "`$$($PSBoundParameters[$item])"
}
$out += " `$attributes.$item = $value`n"
}
}
#add parameter validations
if ($validations) {
Write-Verbose "[$((Get-Date).TimeofDay) PROCESS] Processing validations"
foreach ($validation in $Validations) {
Write-Verbose "[$((Get-Date).TimeofDay) PROCESS] ... $($validation.key)"
$out += "`n # Adding $($validation.key) parameter validation`n"
Switch ($Validation.key) {
"ValidateNotNullOrEmpty" {
$out += " `$v = New-Object System.Management.Automation.ValidateNotNullOrEmptyAttribute`n"
$out += " `$AttributeCollection.Add(`$v)`n"
}
"ValidateLength" {
$out += " `$value = @($($Validation.Value[0]),$($Validation.Value[1]))`n"
$out += " `$v = New-Object System.Management.Automation.ValidateLengthAttribute(`$value)`n"
$out += " `$AttributeCollection.Add(`$v)`n"
}
"ValidateSet" {
$join = "'$($Validation.Value -join "','")'"
$out += " `$value = @($join) `n"
$out += " `$v = New-Object System.Management.Automation.ValidateSetAttribute(`$value)`n"
$out += " `$AttributeCollection.Add(`$v)`n"
}
"ValidateRange" {
$out += " `$value = @($($Validation.Value[0]),$($Validation.Value[1]))`n"
$out += " `$v = New-Object System.Management.Automation.ValidateRangeAttribute(`$value)`n"
$out += " `$AttributeCollection.Add(`$v)`n"
}
"ValidatePattern" {
$out += " `$value = '$($Validation.value)'`n"
$out += " `$v = New-Object System.Management.Automation.ValidatePatternAttribute(`$value)`n"
$out += " `$AttributeCollection.Add(`$v)`n"
}
"ValidateScript" {
$out += " `$value = {$($Validation.value)}`n"
$out += " `$v = New-Object System.Management.Automation.ValidateScriptAttribute(`$value)`n"
$out += " `$AttributeCollection.Add(`$v)`n"
}
"ValidateCount" {
$out += " `$value = @($($Validation.Value[0]),$($Validation.Value[1]))`n"
$out += " `$v = New-Object System.Management.Automation.ValidateCountAttribute(`$value)`n"
$out += " `$AttributeCollection.Add(`$v)`n"
}
} #close switch
} #foreach validation
} #validations
$out += " `$attributeCollection.Add(`$attributes)`n"
if ($Alias) {
Write-Verbose "[$((Get-Date).TimeofDay) PROCESS] Adding parameter alias $($alias -join ',')"
Foreach ($item in $alias) {
$out += "`n # Adding a parameter alias`n"
$out += " `$dynalias = New-Object System.Management.Automation.AliasAttribute -ArgumentList '$Item'`n"
$out += " `$attributeCollection.Add(`$dynalias)`n"
}
}
$out += "`n # Defining the runtime parameter`n"
#handle the Switch parameter since it uses a slightly different name
if ($ParameterType.Name -match "Switch") {
$paramType = "Switch"
}
else {
$paramType = $ParameterType.Name
}
$out += " `$dynParam1 = New-Object -Type System.Management.Automation.RuntimeDefinedParameter('$Name', [$paramType], `$attributeCollection)`n"
if ($DefaultValue) {
Write-Verbose "[$((Get-Date).TimeofDay) PROCESS] Using default value $($DefaultValue)"
if ( $DefaultValue[0] -is [string]) {
$value = "'$($DefaultValue)'"
}
else {
$value = "`$$($DefaultValue)"
}
$out += " `$dynParam1.Value = $value`n"
}
$Out += @"
`$paramDictionary.Add('$Name', `$dynParam1)
"@
} #foreach dynamic parameter name
}
End {
$out += @"
return `$paramDictionary
} # end if
} #end DynamicParam
"@
$out
Write-Verbose "[$((Get-Date).TimeofDay) END ] Ending $($myinvocation.mycommand)"
} #end
}ฟังก์ชันนี้กำหนดพารามิเตอร์ข้อมูลที่คุณอาจต้องการใช้ในพารามิเตอร์ไดนามิกของคุณ ฉันจะไม่เน้นไปที่วิธีการทำงานของฟังก์ชัน แต่จะเน้นไปที่การใช้งานแทน ต้องระบุชื่อและเงื่อนไขของพารามิเตอร์ เงื่อนไขควรเป็นโค้ดที่ทำงานภายในคำสั่ง IF หากคุณรู้ว่าคุณต้องการบางสิ่งที่ซับซ้อนกว่านี้ ให้ใช้ค่าพารามิเตอร์เช่น $True คุณสามารถแก้ไขโค้ดที่สร้างขึ้นได้ในภายหลัง
$splat = @{
ParameterName = "ConsoleGridView"
Condition = "Get-Command -Name Out-ConsoleGridview -ErrorAction SilentlyContinue"
Alias = "ocgv"
HelpMessage = "Use the Out-ConsoleGridView command in PowerShell 7"
Comment = "Offer to use Out-ConsoleGridView if installed in PowerShell 7"
ParameterType = "switch"
}
New-PSDynamicParameter @splat | Set-Clipboardฟังก์ชันจะเขียนสตริงของโค้ด PowerShell ลงในไปป์ไลน์ ฉันกำลังคัดลอกไปที่คลิปบอร์ด
DynamicParam {
# Offer to use Out-ConsoleGridView if installed in PowerShell 7
If (Get-Command -Name Out-ConsoleGridview -ErrorAction SilentlyContinue) {
$paramDictionary = New-Object -Type System.Management.Automation.RuntimeDefinedParameterDictionary
# Defining parameter attributes
$attributeCollection = New-Object -Type System.Collections.ObjectModel.Collection[System.Attribute]
$attributes = New-Object System.Management.Automation.ParameterAttribute
$attributes.ParameterSetName = '__AllParameterSets'
$attributes.HelpMessage = 'Use the Out-ConsoleGridView command in PowerShell 7'
$attributeCollection.Add($attributes)
# Adding a parameter alias
$dynalias = New-Object System.Management.Automation.AliasAttribute -ArgumentList 'ocgv'
$attributeCollection.Add($dynalias)
# Defining the runtime parameter
$dynParam1 = New-Object -Type System.Management.Automation.RuntimeDefinedParameter('ConsoleGridView', [Switch], $attributeCollection)
$paramDictionary.Add('ConsoleGridView', $dynParam1)
return $paramDictionary
} # end if
} #end DynamicParamฉันสามารถแทรกสิ่งนี้ได้หลังจากส่วน Param() ฉันไม่ต้องเขียนโค้ดนี้เลย เมื่อฉันดอทซอร์สฟังก์ชันของฉันใน PowerShell 7 ฉันมีพารามิเตอร์เพิ่มเติม
เนื่องจากพารามิเตอร์ไดนามิกไม่ได้ขึ้นอยู่กับพารามิเตอร์อื่นๆ และฉันปล่อยให้ PowerShell สร้างความช่วยเหลือ ซึ่งก็ไม่ได้แย่เกินไป แต่ในโมดูลที่มีความช่วยเหลือจากภายนอก การจัดทำเอกสารจะยากขึ้นเล็กน้อย แต่มันใช้งานได้แม้จะใช้นามแฝงพารามิเตอร์ไดนามิกก็ตาม
Get-DriveGridView -Computername thinkp1 -ocgvกำลังรับ GUI
แต่เนื่องจากฉันมีแนวโน้มที่จะใช้ฟังก์ชันนี้เพื่อสร้างพารามิเตอร์แบบไดนามิกในตัวแก้ไขสคริปต์ GUI จึงอาจดีกว่า ฟังก์ชันนี้สร้างส่วนหน้า WPF ให้กับฟังก์ชันแรก
Function New-PSDynamicParameterForm {
[cmdletbinding()]
[alias("dpf")]
[Outputtype("None")]
Param()
Add-Type -AssemblyName PresentationFramework
Add-Type -AssemblyName PresentationCore
$list = [System.Collections.Generic.list[object]]::new()
[xml]$xaml = @"
<Window xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:local="clr-namespace:New_DynamicParamForm"
Title="New Dynamic Parameter" Height="475" Width="650" WindowStartupLocation = "CenterScreen" >
<Grid HorizontalAlignment="Center" Width="650" Margin="0,0,0,0">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="0*"/>
<ColumnDefinition/>
</Grid.ColumnDefinitions>
<Label x:Name="label" Content="Parameter Name*" HorizontalAlignment="Left" Height="25" Margin="9,22,0,0" VerticalAlignment="Top" Width="116" Grid.Column="1"/>
<TextBox x:Name="ParameterName" Grid.ColumnSpan="2" HorizontalAlignment="Left" Height="20" Margin="120,25,0,0" Text="" TextWrapping="Wrap" VerticalAlignment="Top" Width="153"/>
<CheckBox x:Name="Mandatory" Content="Mandatory" HorizontalAlignment="Center" Margin="0,27,0,0" VerticalAlignment="Top" Grid.Column="1"/>
<Label x:Name="label_Copy" Content="Parameter Set Name" HorizontalAlignment="Left" Height="25" Margin="307,44,0,0" VerticalAlignment="Top" Width="121" Grid.Column="1"/>
<TextBox x:Name="ParameterSetName" Grid.ColumnSpan="2" HorizontalAlignment="Left" Height="20" Margin="443,46,0,0" Text="" TextWrapping="Wrap" VerticalAlignment="Top" Width="153"/>
<Label x:Name="label1" Content="Comment" Grid.ColumnSpan="2" HorizontalAlignment="Left" Margin="18,392,0,0" VerticalAlignment="Top"/>
<TextBox x:Name="Comment" Grid.ColumnSpan="2" HorizontalAlignment="Left" Margin="87,396,0,0" Text="" TextWrapping="Wrap" VerticalAlignment="Top" Width="345"/>
<Label x:Name="label2" Content="Parameter Alias" Grid.ColumnSpan="2" HorizontalAlignment="Left" Margin="11,51,0,0" VerticalAlignment="Top"/>
<TextBox x:Name="Alias" Grid.ColumnSpan="2" HorizontalAlignment="Left" Height="20" Margin="121,54,0,0" Text="" TextWrapping="Wrap" VerticalAlignment="Top" Width="153"/>
<Label x:Name="label2_Copy" Content="Default Value" Grid.ColumnSpan="2" HorizontalAlignment="Left" Margin="11,78,0,0" VerticalAlignment="Top"/>
<TextBox x:Name="DefaultValue" Grid.ColumnSpan="2" HorizontalAlignment="Left" Height="20" Margin="121,81,0,0" Text="" TextWrapping="Wrap" VerticalAlignment="Top" Width="153"/>
<Button x:Name="OK" Content="_Create" Grid.ColumnSpan="2" HorizontalAlignment="Left" Margin="448,394,0,0" VerticalAlignment="Top" Width="75"/>
<Button x:Name="Quit" Content="Close" Grid.ColumnSpan="2" HorizontalAlignment="Left" Margin="536,394,0,0" VerticalAlignment="Top" Width="75"/>
<Label x:Name="label2_Copy1" Content="Help Message" Grid.ColumnSpan="2" HorizontalAlignment="Left" Margin="281,78,0,0" VerticalAlignment="Top"/>
<TextBox x:Name="HelpMessage" HorizontalAlignment="Left" Height="20" Margin="376,81,0,0" Text="" TextWrapping="Wrap" VerticalAlignment="Top" Width="222" Grid.Column="1"/>
<Label x:Name="label2_Copy2" Content="Parameter Type" Grid.ColumnSpan="2" HorizontalAlignment="Left" Margin="11,105,0,0" VerticalAlignment="Top"/>
<TextBox x:Name="ParameterType" Grid.ColumnSpan="2" HorizontalAlignment="Left" Height="20" Margin="121,108,0,0" Text="string" TextWrapping="Wrap" VerticalAlignment="Top" Width="153"/>
<Label x:Name="label3" Content="Condition*" Grid.ColumnSpan="2" HorizontalAlignment="Left" Margin="13,132,0,0" VerticalAlignment="Top"/>
<TextBox x:Name="Condition" Grid.ColumnSpan="2" HorizontalAlignment="Left" Margin="123,137,0,0" Text="" TextWrapping="Wrap" VerticalAlignment="Top" Width="282"/>
<Border BorderThickness="1" BorderBrush="Black" Grid.ColumnSpan="2" HorizontalAlignment="Left" Height="1" Margin="10,162,0,0" VerticalAlignment="Top" Width="634"/>
<Label x:Name="label4" Content="Parameter Validations" Grid.ColumnSpan="2" HorizontalAlignment="Left" Margin="7,166,0,0" VerticalAlignment="Top"/>
<CheckBox x:Name="ValidateNotNullOrEmpty" Content="ValidateNotNullorEmpty" Grid.ColumnSpan="2" HorizontalAlignment="Left" Margin="39,196,0,0" VerticalAlignment="Top"/>
<Label x:Name="label5" Content="ValidateCount" Grid.ColumnSpan="2" HorizontalAlignment="Left" Margin="35,212,0,0" VerticalAlignment="Top"/>
<TextBox x:Name="ValidateCount" HorizontalAlignment="Left" Margin="124,216,0,0" Text="" TextWrapping="Wrap" VerticalAlignment="Top" Width="60" Grid.Column="1"/>
<Label x:Name="label5_Copy" Content="ValidateLength" HorizontalAlignment="Left" Margin="210,212,0,0" VerticalAlignment="Top" Grid.Column="1"/>
<TextBox x:Name="ValidateLength" HorizontalAlignment="Left" Margin="303,216,0,0" Text="" TextWrapping="Wrap" VerticalAlignment="Top" Width="60" Grid.Column="1"/>
<CheckBox x:Name="ValueFromPipelineByPropertyName" Content="ValueFromPipelineByPropertyName" Grid.ColumnSpan="2" HorizontalAlignment="Left" Margin="201,195,0,0" VerticalAlignment="Top"/>
<Label x:Name="label6" Content="ValidateRange" Grid.ColumnSpan="2" HorizontalAlignment="Left" Margin="394,212,0,0" VerticalAlignment="Top"/>
<TextBox x:Name="ValidateRange" Grid.ColumnSpan="2" HorizontalAlignment="Left" Margin="481,216,0,0" Text="" TextWrapping="Wrap" VerticalAlignment="Top" Width="120"/>
<Label x:Name="label5_Copy1" Content="ValidatePattern" Grid.ColumnSpan="2" HorizontalAlignment="Left" Margin="35,242,0,0" VerticalAlignment="Top"/>
<TextBox x:Name="ValidatePattern" HorizontalAlignment="Left" Margin="125,245,0,0" Text="" TextWrapping="Wrap" VerticalAlignment="Top" Width="150" Grid.Column="1"/>
<Label x:Name="label5_Copy2" Content="ValidateScript" Grid.ColumnSpan="2" HorizontalAlignment="Left" Margin="35,270,0,0" VerticalAlignment="Top"/>
<TextBox x:Name="ValidateScript" AcceptsReturn = "True" VerticalScrollBarVisibility="Auto" Grid.ColumnSpan="2" HorizontalAlignment="Left" Margin="121,274,0,0" Text="" TextWrapping="Wrap" VerticalAlignment="Top" Width="250" Height="70"/>
<Label x:Name="label7" Content="ValidateSet" Grid.ColumnSpan="2" HorizontalAlignment="Left" Margin="34,351,0,0" VerticalAlignment="Top"/>
<TextBox x:Name="ValidateSet" Grid.ColumnSpan="2" HorizontalAlignment="Left" Height="16" Margin="117,356,0,0" Text="" TextWrapping="Wrap" VerticalAlignment="Top" Width="328"/>
</Grid>
</Window>
"@
$reader = New-Object System.Xml.XmlNodeReader $xaml
$Window = [Windows.Markup.XamlReader]::Load($reader)
#get all parameters
$all = (Get-Command New-PSDynamicParameter).parameters
#filter out common parameters
$common = [System.Management.Automation.Cmdlet]::CommonParameters
$paramList = $all.GetEnumerator().where({$common -notcontains $_.key}).key
#get controls
foreach ($item in $paramList) {
Write-Verbose "Processing control $item"
Try {
$tmp = New-Variable -Name $item -Value ($Window.FindName($item)) -ErrorAction Stop -PassThru
#add a help tool tip
$tip = $all[$item].attributes.where({$_.typeid.name -eq 'parameterattribute'}).helpMessage
write-Verbose "Found help $tip"
$tmp.Value.ToolTip = $tip
$list.Add((Get-Variable -Name $item))
}
Catch {
Write-Verbose "Skipping $item"
}
}
#hook up code to buttons
$OK = $Window.FindName("OK")
$OK.ToolTip = "Create the dynamic parameter code and copy to the clipboard.`nThis will NOT close the form."
$OK.Add_Click({
Write-Verbose "Defining dynamic parameter $($ParameterName.text)"
$splat = @{}
$list | where-object {$_.value.text} | foreach-object {
$splat.Add($_.Name,$_.value.Text)
}
#add switches
$list | where-object {$_.value.IsChecked} | foreach-object {
$splat.Add($_.Name,$True)
}
#turn values into arrays as needed
$Names = "ValidateSet","ValidateCount","ValidateRange","ValidateLength"
foreach ($n in $names) {
if ($splat[$n]) {
$splat[$n] = $splat[$n].split(",")
}
}
#convert ValidateScript text into a scriptblock
if ($splat["ValidateScript"]) {
$splat["ValidateScript"] = [scriptblock]::Create($splat["ValidateScript"])
}
New-PSDynamicParameter @splat | Set-Clipboard
Write-Host "Your dynamic parameter code has been copied to the clipboard. Paste it into your script file." -ForegroundColor Green
})
$Quit = $Window.FindName("Quit")
$Quit.Add_Click({$window.close()})
[void]$window.Activate()
[void]$window.ShowDialog()
}ในไฟล์ .ps1 ที่กำหนดฟังก์ชันเหล่านี้ ฉันยังใช้โค้ดนี้เพื่อสร้างทางลัดหากคุณดอทซอร์สไฟล์ใน VS Code หรือ PowerShell ISE
#add scripting editor shortcuts or you can run the functions in the editor's console window.
if ($host.name -eq 'Visual Studio Code Host') {
Register-EditorCommand -Name "DynamicParameterForm" -DisplayName "Define a dynamic parameter" -ScriptBlock (Get-Item -path Function:\New-PSDynamicParameterForm).scriptblock -SuppressOutput
}
elseif ($host.name -match "PowerShell ISE") {
if ($psise.CurrentPowerShellTab.AddOnsMenu.Submenus.DisplayName -notcontains "New Dynamic Parameter") {
$action = {New-PSDynamicParameterForm}
[void]($Psise.CurrentPowerShellTab.AddOnsMenu.Submenus.Add("New Dynamic Parameter", $action, "Ctrl+Alt+D"))
}
}การรันคำสั่งจะสร้างแบบฟอร์ม WPF นี้
ฉันได้สร้างข้อมูลคำแนะนำเครื่องมือแบบไดนามิกสำหรับแต่ละรายการตามข้อความช่วยเหลือของ New-PSDynamicParameterForm ค่าบังคับจะแสดงด้วยเครื่องหมายดอกจัน ฉันเห็นว่าฉันอาจต้องปรับแต่งกล่องข้อความเงื่อนไข
ไม่ว่าเมื่อคุณคลิกสร้าง ฟังก์ชันจะสร้างโค้ดพารามิเตอร์แบบไดนามิกและคัดลอกไปยังคลิปบอร์ด จากนั้นคุณสามารถวางลงในฟังก์ชันของคุณได้ แบบฟอร์มจะยังคงเปิดอยู่จนกว่าคุณจะคลิกปิด วิธีนี้ช่วยให้คุณปรับแต่งพารามิเตอร์อย่างละเอียดโดยไม่ต้องป้อนทุกอย่างใหม่
อย่างไรก็ตาม หากคุณสนใจ นี่คือฟังก์ชัน Get-DriveGridView ที่อัปเดตแล้ว
Function Get-DriveGridView {
[cmdletbinding(DefaultParameterSetName = "computer")]
[OutputType("none","object")]
Param(
[parameter(Position = 0, ValueFromPipeline, ParameterSetName = "computer")]
[ValidateNotNullOrEmpty()]
[string]$Computername = $env:COMPUTERNAME,
[parameter(ValueFromPipeline, ParameterSetName = "session")]
[ValidateNotNullOrEmpty()]
[Microsoft.Management.Infrastructure.CimSession]$CimSession,
[Parameter(HelpMessage = "Enter a title to use for the GridView")]
[ValidateNotNullOrEmpty()]
[string]$Title = "Drive Report",
[Parameter(HelpMessage = "pass results to the pipeline in addition to the grid view")]
[switch]$Passthru
)
DynamicParam {
# Offer to use Out-ConsoleGridView if installed in PowerShell 7
If (Get-Command -Name Out-ConsoleGridview -ErrorAction SilentlyContinue) {
$paramDictionary = New-Object -Type System.Management.Automation.RuntimeDefinedParameterDictionary
# Defining parameter attributes
$attributeCollection = New-Object -Type System.Collections.ObjectModel.Collection[System.Attribute]
$attributes = New-Object System.Management.Automation.ParameterAttribute
$attributes.ParameterSetName = '__AllParameterSets'
$attributes.HelpMessage = 'Use the Out-ConsoleGridView command in PowerShell 7'
$attributeCollection.Add($attributes)
# Adding a parameter alias
$dynalias = New-Object System.Management.Automation.AliasAttribute -ArgumentList 'ocgv'
$attributeCollection.Add($dynalias)
# Defining the runtime parameter
$dynParam1 = New-Object -Type System.Management.Automation.RuntimeDefinedParameter('ConsoleGridView', [Switch], $attributeCollection)
$paramDictionary.Add('ConsoleGridView', $dynParam1)
return $paramDictionary
} # end if
} #end DynamicParam
Begin {
Write-Verbose "[$((Get-Date).TimeofDay) BEGIN ] Starting $($myinvocation.mycommand)"
Write-Verbose "[$((Get-Date).TimeofDay) BEGIN ] Collecting drive information...please wait"
#initialize a list to hold the results
$results = [System.Collections.Generic.list[object]]::new()
#hashtable of Get-CimInstance parameters for splatting
$splat = @{
Classname = "win32_logicaldisk"
Filter = "drivetype=3"
ErrorAction = "Stop"
Property = "SystemName", "DeviceID", "Size", "Freespace"
}
} #begin
Process {
If ($pscmdlet.ParameterSetName -eq 'computer') {
Write-Verbose "[$((Get-Date).TimeofDay) PROCESS] Getting data from computer $($computername.toUpper())"
$splat["Computername"] = $Computername
$remote = $Computername.ToUpper()
}
else {
Write-Verbose "[$((Get-Date).TimeofDay) PROCESS] Getting data from cimsession $($cimsession.computername.toUpper())"
$splat["CimSession"] = $cimSession
$remote = $cimSession.computername.toUpper()
}
Try {
Get-CimInstance @splat | Select-Object -Property @{Name = "Computername"; Expression = { $_.Systemname } },
@{Name = "Drive"; Expression = { $_.DeviceID } },
@{Name = "SizeGB"; Expression = { [int]($_.Size / 1GB) } },
@{Name = "FreeGB"; Expression = { [int]($_.Freespace / 1GB) } },
@{Name = "UsedGB"; Expression = { [math]::round(($_.size - $_.Freespace) / 1GB, 2) } },
@{Name = "Free%"; Expression = { [math]::round(($_.Freespace / $_.Size) * 100, 2) } },
@{Name = "FreeGraph"; Expression = {
[int]$per = (($_.Freespace / $_.Size) * 100/2)
"|" * $per }
} | ForEach-Object { $results.Add($_) }
} #try
Catch {
Write-Warning "Failed to get drive data from $remote. $($_.exception.message)"
}
} #process
End {
#send the results to Out-Gridview
Write-Verbose "[$((Get-Date).TimeofDay) END ] Found $($results.count) total items"
if ($results.count -gt 1) {
if ($PSBoundParameters.ContainsKey("ConsoleGridView")) {
$Results | Sort-Object -Property Computername | Out-ConsoleGridView -Title $Title
}
else {
$Results | Sort-Object -Property Computername | Out-GridView -Title $Title
}
if ($Passthru) {
$Results
}
}
else {
Write-Warning "No drive data found to report."
}
Write-Verbose "[$((Get-Date).TimeofDay) END ] Ending $($myinvocation.mycommand)"
} #end
}ลองมัน
ทั้งฟังก์ชันและโค้ดการตรวจจับตัวแก้ไขสคริปต์อยู่ในไฟล์ .ps1 ไฟล์เดียวซึ่งฉันระบุแหล่งที่มา ฉันไม่ต้องการพารามิเตอร์แบบไดนามิกบ่อยครั้ง แต่เมื่อฉันต้องการ ฉันคิดว่าสิ่งนี้จะช่วยฉันประหยัดเวลาได้มาก ฉันหวังว่าคุณจะลองดูและแจ้งให้เราทราบว่าคุณคิดอย่างไรหรือมันทำงานอย่างไรสำหรับคุณ ฉันกำลังพิจารณาที่จะเพิ่มมันลงในโมดูล PSScriptTools ซึ่งดูเหมือนเป็นบ้านในอุดมคติ แต่ฉันก็อยากได้คำติชมก่อนที่จะดำเนินการขั้นนั้น



