使用 foreach 更改开关行为

Change switch behavoir with foreach

我有一个 XML 文件包含:

<Setting>
    <Application Id="Main_Form" Name="Office365: Run scripts">
        <task Id="1" Script="SPO-SCDefaults.ps1" Name="Create default Site Collection structure" />
        <task Id="2" Script="SPO-FileMig.ps1" Name="Datacopy to SharePoint cloud" />
        <task Id="3" Script="EXO-AddAdminDistri.ps1" Name="Exchange: Add admin user to distributiongroups" />
        <task Id="4" Script="empty.ps1" Name="Todo..." />
    </Application>
</Setting>

还有这样的脚本:

$Xml = [xml](Get-Content $ScriptPath\Settings.xml)

function Do-PromptTask
{   
    $task1 = $Xml.Setting.Application.task.name[0]
    $task2 = $Xml.Setting.Application.task.name[1]
    $task3 = $Xml.Setting.Application.task.name[2]
    $task4 = $Xml.Setting.Application.task.name[3]
    $task1_exec = $Xml.Setting.Application.task.script[0]
    $task2_exec = $Xml.Setting.Application.task.script[1]
    $task3_exec = $Xml.Setting.Application.task.script[2]
    $task4_exec = $Xml.Setting.Application.task.script[3]

    switch -wildcard (Prompt-SelectionList "Chose task to run:" @($task1,$task2,$task3,$task4))
    {
        $task1{$task_result = $task1_exec}
        $task2{$task_result = $task2_exec}
        $Task3{$task_result = $task3_exec}
        $Task4{$task_result = $task4_exec}
        ""{Exit} #End Selection (cancel selected)
        "*"{Do-PromptTask} #Keep prompting until "cancel" selected
    }
    Write-Host "$ScriptPath\Bin$task_result"
}

Do-PromptTask

我认为将其更改为类似内容应该更容易:

function Do-PromptTask
{
    switch -wildcard (Prompt-SelectionList "Chose task to run:" @($task['name'])) # Array of all names
    {
        foreach ($node in $Xml.Setting.Application.task) {
            $task['name']{$task_result = $task_exec['script']}
        }
        ""{Exit} #End Selection (cancel selected)
        "*"{Do-PromptTask} #Keep prompting until "cancel" selected
    }
    Write-Host "$ScriptPath\Bin$task_result"
}

Do-PromptTask

这可能吗,我的方法是否正确?我希望能够在 XML

中添加项目时动态生成表单中的列表

我想我会完全避免使用 switch,而是这样做:

function Do-PromptTask
{   
    $sel = $null
    while ($Xml.Setting.Application.task.name -notcontains $sel) {
        $sel = Prompt-SelectionList "Chose task to run:" $Xml.Setting.Application.task.name
        if ([String]::IsNullOrEmpty($sel)) {
            exit
        }
    }
    $task_result = & ($Xml.Setting.Application.task | Where-Object { $_.name -eq $sel } | Select-Object -ExpandProperty Script)

    Write-Host "$ScriptPath\Bin$task_result"
}

基本上利用 XML 的数组属性,从不引用单个索引。

我也不会为此使用 Switch,因为您希望它像那样动态。我会使用一个哈希表,其中您的任务名称作为键,您的任务可执行文件作为脚本块形式的值。像这样:

Do{
    $AllTasks = @{}
    $Xml.Setting.Application.task | ForEach{$AllTasks.add($_.Name,[scriptblock]::Create($_.Script))}
    $Sel = Prompt-SelectionList "Chose task to run:" $AllTasks.Keys
    If(!$Sel -match "Cancel"){$AllTasks[$Sel].Invoke()}
}While($Sel -notmatch "Cancel")

我使用来自@TheMadTechnician 的代码找到了答案,在执行表单的代码下方和 returns 路径中的脚本名称。相当大的挑战,但它适用于 XML 并且是动态的。

$Xml = [xml](Get-Content $ScriptPath\Settings.xml)
. "$ScriptPath\Bin\O365-Functions.ps1"

$Sel = $null

Do {
    $AllTasks = @{}

    $Xml.Setting.Application.task | ForEach { $AllTasks.add($_.Name,[scriptblock]::Create($_.Script)) }
    $Sel = Prompt-SelectionList "Chose task to run:" @($AllTasks.Keys)

    $TaskResult = $ScriptPath+"\Bin\"+$AllTasks[$Sel].ToString()
    Invoke-Expression "&'$TaskResult'"

} While( $Sel -notmatch $null )

感谢您的帮助!