【问题标题】:Accessing dynamically created variables inside a powershell function在 powershell 函数中访问动态创建的变量
【发布时间】:2018-02-28 19:39:24
【问题描述】:

我一直在编写这个脚本,这个脚本在概念上看起来很简单,但确实让我难以置信,有些东西似乎不像我期望的那样工作。基本思想是脚本将读取一组用户名并为用户提供一个复选框,他们可以检查他们希望系统创建的每个帐户。在这个站点的帮助下,我能够获得一个能够动态创建变量和复选框对象的函数,但现在我在访问它们的值时遇到了问题。无论是否选中该框,我只需要为每个名称提取一个布尔值。完整代码如下:

$form = New-Object System.Windows.Forms.Form
$flowlayoutpanel = New-Object System.Windows.Forms.FlowLayoutPanel
$buttonOK = New-Object System.Windows.Forms.Button


$usernames = "andrew", "beth", "charlie", "dave", "james", "george"
$totalvalues = ($usernames.count)

$formsize = 85 + (30 * $totalvalues)
$flowlayoutsize = 10 + (30 * $totalvalues)
$buttonplacement = 40 + (30 * $totalvalues)

$form_Load = {
    foreach($user in $usernames){
        $DynamicCheckBox = New-Variable -Name ("checkbox" + $user)
        $DynamicCheckBox = New-object System.Windows.Forms.CheckBox

        $DynamicCheckBox.Margin = '10, 8, 0, 0'
        $DynamicCheckBox.Name = 'checkbox' + $_
        $DynamicCheckBox.Size = '200, 22'
        $DynamicCheckBox.Text = "" + $user
        $DynamicCheckBox.TextAlign = 'MiddleLeft'
        $flowlayoutpanel.Controls.Add($DynamicCheckBox)
    }       
}

$form.Controls.Add($flowlayoutpanel)
$form.Controls.Add($buttonOK)
$form.AcceptButton = $buttonOK
$form.AutoScaleDimensions = '8, 17'
$form.AutoScaleMode = 'Font'
$form.ClientSize = "500 , $formsize"
$form.FormBorderStyle = 'FixedDialog'
$form.Margin = '5, 5, 5, 5'
$form.MaximizeBox = $False
$form.MinimizeBox = $False
$form.Name = 'form1'
$form.StartPosition = 'CenterScreen'
$form.Text = 'Form'
$form.add_Load($form_Load)

$flowlayoutpanel.BorderStyle = 'FixedSingle'
$flowlayoutpanel.Location = '48, 13'
$flowlayoutpanel.Margin = '4, 4, 4, 4'
$flowlayoutpanel.Name = 'flowlayoutpanel1'
$flowlayoutpanel.Size = "400, $flowlayoutsize"
$flowlayoutpanel.TabIndex = 1

$buttonOK.Anchor = 'Bottom, Right'
$buttonOK.DialogResult = 'OK'
$buttonOK.Location = "383, $buttonplacement"
$buttonOK.Margin = '4, 4, 4, 4'
$buttonOK.Name = 'buttonOK'
$buttonOK.Size = '100, 30'
$buttonOK.TabIndex = 0
$buttonOK.Text = '&OK'


$form.ShowDialog()

    foreach($user in $usernames){
        $DynamicCheckBoxValue = Get-Variable -Name ('$checkbox' + $user) -Scope Script
        write-host $DynamicCheckBoxValue

    }  

write-host $checkbox.Checked

我尝试使用第 15 行中创建的变量的范围设置,但如果我按照我的想法将范围更改为脚本,我会收到一系列奇怪的错误。 Powershell 告诉我该变量已经存在(尽管这可能是因为它们仍在我的 ISE 会话中?)。如果我告诉它强制覆盖任何可能修复该错误的内容,但无论哪种方式,我都会收到告诉我该变量不存在的错误,即使就在 powershell 抱怨变量已经 did 存在。

Get-Variable : Cannot find a variable with the name '$checkboxgeorge'.
At C:\Users\sheep\Untitled1.ps1:62 char:33
+ ...      $DynamicCheckBoxValue = Get-Variable -Name ('$checkbox' + $user)
+                                  ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
    + CategoryInfo          : ObjectNotFound: ($checkboxgeorge:String) [Get-Variable], ItemNotFoundException
    + FullyQualifiedErrorId : VariableNotFound,Microsoft.PowerShell.Commands.GetVariableCommand

我不确定这里发生了什么,我正在摆弄范围,因为 似乎 像罪魁祸首。如果这里有人知道解决方法是什么,你能告诉我为什么会这样吗?

【问题讨论】:

  • 您的意思是:$DynamicCheckBoxValue = Get-Variable -Name ('checkbox' + $user) 没有$ 符号吗?
  • 在这个站点的帮助下,我能够获得一个能够动态创建变量的函数” - 这不是一个帮助,而是一个障碍。请参阅之前关于此主题的咆哮/回答:stackoverflow.com/a/40477933/478656

标签: function powershell variables scope


【解决方案1】:

即使我提交了这个答案,我还是强烈建议您阅读 TesselatingHeckler here 的这个答案,他在 cmets 部分向您提供了该答案。

此外,虽然动态变量是一个东西,但在你的情况下,这是一个被证明是无用的层,并且在这可以更简单时添加复杂的逻辑。

比动态变量更好的解决方案适合您的场景。

例如,不要创建用户名数组,而是使用哈希表,该哈希表仍将存储您的用户名,但将有一个“值”字段,您可以使用该字段来存储您的布尔值,并且很快,当您有更复杂的东西时,您可以在值字段中存储完整的对象。

$usernames = 
            @{
            'andrew'='';
            'beth'='';
            'charlie'='';
            'dave'='';
            'james'=''
            'george'=''
            }

现在您已经有了哈希表,您可以使用

设置您的值
#Settings some value - in your case, that would be done through the form
$usernames.andrew = 0 
$usernames.dave = 1

你甚至可以“动态地”做到这一点

$User = Read-Host  # Asking which user here
$usernames.Item($User) = 1 # setting user "checkbox value" to 1 here

例如,在最后一个示例中,用户名存储在 $User 中,然后将该用户的值设置为 '1' 。

它为您提供所需的一切,而无需设置动态变量的开销。

一个简单的语句来显示谁选中了他们的复选框。 由于所有内容都在 $Usernames 哈希表中,因此无需任何额外工作即可轻松操作、存储到 csv 文件等。

# Display users checked status their checkboxes
$usernames | ft Name, @{n='IsChecked';e={$_.Value -eq 1}}

【讨论】:

  • 好的,我现在知道哈希表是一种更好的方法了。
【解决方案2】:

下一行没有对变量 $DynamicCheckBox 进行任何更改。

$DynamicCheckBox = New-Variable -Name ("checkbox" + $user)

我已修改脚本以找出检查了哪些用户。希望这会有所帮助。

代码:-

    $form = New-Object System.Windows.Forms.Form
    $flowlayoutpanel = New-Object System.Windows.Forms.FlowLayoutPanel
    $buttonOK = New-Object System.Windows.Forms.Button


    $usernames = "andrew", "beth", "charlie", "dave", "james", "george"
    $totalvalues = ($usernames.count)

    $formsize = 85 + (30 * $totalvalues)
    $flowlayoutsize = 10 + (30 * $totalvalues)
    $buttonplacement = 40 + (30 * $totalvalues)

    $script:CheckBoxArray = @()

    $form_Load = {

       foreach($user in $usernames){

            $DynamicCheckBox = New-object System.Windows.Forms.CheckBox

            $DynamicCheckBox.Margin = '10, 8, 0, 0'
            $DynamicCheckBox.Name = $user
            $DynamicCheckBox.Size = '200, 22'
            $DynamicCheckBox.Text = "" + $user
            $DynamicCheckBox.TextAlign = 'MiddleLeft'
            $flowlayoutpanel.Controls.Add($DynamicCheckBox)
            $script:CheckBoxArray += $DynamicCheckBox
        }       
    }

    $form.Controls.Add($flowlayoutpanel)
    $form.Controls.Add($buttonOK)
    $form.AcceptButton = $buttonOK
    $form.AutoScaleDimensions = '8, 17'
    $form.AutoScaleMode = 'Font'
    $form.ClientSize = "500 , $formsize"
    $form.FormBorderStyle = 'FixedDialog'
    $form.Margin = '5, 5, 5, 5'
    $form.MaximizeBox = $False
    $form.MinimizeBox = $False
    $form.Name = 'form1'
    $form.StartPosition = 'CenterScreen'
    $form.Text = 'Form'
    $form.add_Load($($form_Load))

    $flowlayoutpanel.BorderStyle = 'FixedSingle'
    $flowlayoutpanel.Location = '48, 13'
    $flowlayoutpanel.Margin = '4, 4, 4, 4'
    $flowlayoutpanel.Name = 'flowlayoutpanel1'
    $flowlayoutpanel.AccessibleName = 'flowlayoutpanel1'
    $flowlayoutpanel.Size = "400, $flowlayoutsize"
    $flowlayoutpanel.TabIndex = 1

    $buttonOK.Anchor = 'Bottom, Right'
    $buttonOK.DialogResult = 'OK'
    $buttonOK.Location = "383, $buttonplacement"
    $buttonOK.Margin = '4, 4, 4, 4'
    $buttonOK.Name = 'buttonOK'
    $buttonOK.Size = '100, 30'
    $buttonOK.TabIndex = 0
    $buttonOK.Text = '&OK'


    $form.ShowDialog()

        foreach($cbox in $CheckBoxArray){
            $cbox.Name + " is " + $cbox.CheckState

        }  

    Remove-Variable checkbox*

输入:-

输出:-

【讨论】:

    【解决方案3】:

    这可能会将您推向正确的方向。

    当您使用Get-Variable 时,您必须排除$。所以使用: Get-Variable -Name ("checkbox" + $user) -Scope Script

    【讨论】:

      猜你喜欢
      • 2021-08-13
      • 2014-02-24
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2010-09-12
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多