创建for循环以合并PowerShell菜单驱动的脚本

时间:2014-07-01 16:38:35

标签: powershell

我一直在编写一个脚本来安装需要多个安装程序才能正常工作的产品。某些功能需要安装某些功能,而其他功能则是可选功能。我的脚本是菜单驱动的,它使可选的安装程序和工作得相当好。

大部分代码都被重用了,我想把它整合到一个for循环中,但是我的PShell-foo还没有黑带级别。我熟悉多变量for循环的CSV输入,但认为这可以通过代码中生成的数组来完成。你们其中一位大师能训练这个新手吗?

以下是当前代码的清理版本:

# Main Level Menu Choices
switch (Read-Host $Main_Prompt)
    {
        1 {$choice = 1}
        2 {$choice = 2}
        3 {$choice = 3}
        4 {$choice = 4}
        5 {$choice = 5}
        "q" {$choice = q}
    }

if (($choice -eq "q"){
    Write-host "Exiting!"
    exit
}

# Install 1
if (($choice -eq 1) -or ($choice -eq 5)){
    Write-Host "Installing 1"
    $1Path = "$InstallSource\Folder1\file.msi"
    if (Test-Path $1Path) {
        $processInfo = New-Object System.Diagnostics.ProcessStartInfo "msiexec.exe"
        $processInfo.arguments = "/i `"$1Path`" /qr ARGUMENTS"
        $processMSI = New-Object System.Diagnostics.Process
        $processMSI.StartInfo = $processInfo
        $processMSI.Start() | Out-Null
        $processMSI.WaitforExit()

        if ($processMSI.ExitCode -ne 0) {
            Write-Host "The Installer generated error code:" $processMSI.ExitCode "Exiting!"
            exit
        }
    }
    Else {
        Write-host "Installer does not exist. Exiting!"
        exit
    }
}

# Install 2
if (($choice -eq 2) -or ($choice -eq 5)){
    Write-Host "Installing 2"
    $2Path = "$InstallSource\Folder2\file.msi"
    $processInfo = New-Object System.Diagnostics.ProcessStartInfo "msiexec.exe"
    $processInfo.arguments = "/i `"$2Path`" /qr ARGUMENTS"
    $processMSI = New-Object System.Diagnostics.Process
    $processMSI.StartInfo = $processInfo
    # Write-host $ProcessInfo.arguments
    $processMSI.Start() | Out-Null
    $processMSI.WaitforExit()

    if ($processMSI.ExitCode -ne 0) {
        Write-Host "The Installer generated error code:" $processMSI.ExitCode "Exiting!"
        exit
    }
}

# Install 3
if (($choice -eq 3) -or ($choice -eq 5)){
    Write-Host "Installing 3"
    $3Path = "$InstallSource\Folder3\file.exe"
    $processInfo = New-Object System.Diagnostics.ProcessStartInfo $3Path
    $processInfo.arguments = "/S /v`" ARGUMENTS`""
    $processEXE = New-Object System.Diagnostics.Process
    $processEXE.StartInfo = $processInfo
    $processEXE.Start() | Out-Null
    $processEXE.WaitforExit()

    if ($processEXE.ExitCode -ne 0) {
        Write-Host "The Installer generated error code:" $processEXE.ExitCode "Exiting!"
        exit
    }
}

# Install 4
if (($choice -eq 4) -or ($choice -eq 5)){
    Write-Host "Checking for the Desktop-Experience Feature"
    $DEStatus = Get-WindowsFeature Desktop-Experience
    if( $DEStatus.Installed -ne "True" ) {
        Write-Host "Installing Desktop-Experience Feature"
        Import-Module ServerManager
        Add-WindowsFeature -Name Desktop-Experience
    }
    Write-Host "Installing 4"
    $4Path = "$InstallSource\Folder4\file.exe"
    $processInfo = New-Object System.Diagnostics.ProcessStartInfo $4Path
    $processInfo.arguments = "ARGUMENTS"
    $processEXE = New-Object System.Diagnostics.Process
    $processEXE.StartInfo = $processInfo
    $processEXE.Start() | Out-Null
    $processEXE.WaitforExit()

    if ($processEXE.ExitCode -ne 0) {
        Write-Host "The Installer generated error code:" $processEXE.ExitCode "Exiting!"
        exit
    }

    # Install 5
    Write-Host "Installing 5"
    $5Path = "$InstallSource\Folder5\file.exe"
    $processInfo = New-Object System.Diagnostics.ProcessStartInfo $5Path
    $processInfo.arguments = "ARGUMENTS"
    $processEXE = New-Object System.Diagnostics.Process
    $processEXE.StartInfo = $processInfo
    $processEXE.Start() | Out-Null
    $processEXE.WaitforExit()

    if ($processEXE.ExitCode -ne 0) {
        Write-Host "The Installer generated error code:" $processEXE.ExitCode "Exiting!"
        exit
    }
}

# Install 6
if (($choice -eq 3) -or ($choice -eq 5)){
    Write-Host "Installing 6"
    $6Path = "$InstallSource\Folder6\file.exe"
    $processInfo = New-Object System.Diagnostics.ProcessStartInfo $6Path
    $processInfo.arguments = "ARGUMENTS"
    $processEXE = New-Object System.Diagnostics.Process
    $processEXE.StartInfo = $processInfo
    $processEXE.Start() | Out-Null
    $processEXE.WaitforExit()

    if ($processEXE.ExitCode -ne 0) {
        Write-Host "The Installer generated error code:" $processEXE.ExitCode "Exiting!"
        exit
    }
}

# Install 7
if (($choice -eq 4) -or ($choice -eq 5)){
    Write-Host "Installing 7"
    $7Path = "$InstallSource\Folder7\file.exe"
    $processInfo = New-Object System.Diagnostics.ProcessStartInfo $7Path
    $processInfo.arguments = "ARGUMENTS"
    $processEXE = New-Object System.Diagnostics.Process
    $processEXE.StartInfo = $processInfo
    $processEXE.Start() | Out-Null
    $processEXE.WaitforExit()

    if ($processEXE.ExitCode -ne 0) {
        Write-Host "The Installer generated error code:" $processEXE.ExitCode "Exiting!"
        exit
    }
}

编辑:以TheMadTechnician的代码为例,我对其进行了简化并运行它以查看发生了什么。这是测试代码:

$App1 = "Write-host App1"
$App2 = "Write-host App2"
$App3 = "Write-host App3"
$App4 = "Write-host App4"
$App5 = "Write-host App5"
$App6 = "Write-host App6"
$App7 = "Write-host App7"

# Main Level Menu Choices
$Main_Prompt = '
[1] Choice1
[2] Choice2
[3] Choice3
[4] Choice4
[5] Choice5
[q] Quit
'

switch (Read-Host $Main_Prompt)
    {
        {$_ -eq 1 -or $_ -eq 5} {$ToInstall += $App1}
        {$_ -eq 2 -or $_ -eq 5} {$ToInstall += $App2}
        {$_ -eq 3 -or $_ -eq 5} {$App3,$App4|%{If(!($ToInstall -contains $_)){$ToInstall += $_}}}
        {$_ -eq 4 -or $_ -eq 5} {$App5,$App6,$App7|%{If(!($ToInstall -contains $_)){$ToInstall += $_}}}
        {$_ -ieq "q"} {Write-host "Exiting!";Exit}
    }

ForEach($App in ($ToInstall | Select -Unique)){
    Invoke-Expression $App
}

这是结果(在代码块中,因为我还不能发布图像):

PS C:\temp> .\test.ps1

[1] Choice1
[2] Choice2
[3] Choice3
[4] Choice4
[5] Choice5
[q] Quit
: 5
App1Write-host App2Write-host App3Write-host App4Write-host App5Write-host App6Write-host App7
PS C:\temp>

看来该块执行第一个命令,但只是将其余部分打印到屏幕上。我非常不喜欢这个。

2 个答案:

答案 0 :(得分:2)

我认为你要找的东西会更好(将代码从158行减少到43行)......

创建一个空数组,并定义应用程序路径(或将其移动到交换机,当您看到交换机时,这可能对您更有意义)。在交换机中创建定义应用程序标题的对象,以及该应用程序的安装程序的路径。然后执行ForEach循环,选择唯一对象并安装它们:

$ToInstall = @()
$App1 = [PSCustomObject]@{Name="App1 Name";Path="$InstallSource\Folder1\file.msi";Args="/I ""$InstallSource\Folder1\file.msi"" /qn-!"}
$App2 = [PSCustomObject]@{Name="App2 Name";Path="$InstallSource\Folder2\file.msi";Args="/I ""$InstallSource\Folder2\file.msi"" /qb"}
$App3 = [PSCustomObject]@{Name="App3 Name";Path = "$InstallSource\Folder3\file.msi";Args="/I ""$InstallSource\Folder3\file.msi"" /qn"}
$App4 = [PSCustomObject]@{Name="App4 Name";Path = "$InstallSource\Folder4\file.msi";Args="/I ""$InstallSource\Folder4\file.msi"" /qb-!"}
$App5 = [PSCustomObject]@{Name="App5 Name";Path = "$InstallSource\Folder5\file.msi";Args="/I ""$InstallSource\Folder5\file.msi"" /qn"}
$App6 = [PSCustomObject]@{Name="App6 Name";Path = "$InstallSource\Folder6\file.msi";Args="/I ""$InstallSource\Folder6\file.msi"" /qb-! REBOOT=ReallySuppress"}
$App7 = [PSCustomObject]@{Name="App7 Name";Path = "$InstallSource\Folder7\file.msi";Args="/I ""$InstallSource\Folder7\file.msi"" /qr"}

# Main Level Menu Choices
switch (Read-Host $Main_Prompt)
    {
        {$_ -eq 1 -or $_ -eq 5} {$ToInstall += $App1}
        {$_ -eq 2 -or $_ -eq 5} {$ToInstall += $App2}
        {$_ -eq 3 -or $_ -eq 5} {$App3,$App6,$App7|%{If(!($ToInstall -contains $_)){$ToInstall += $_}}}
        {$_ -eq 4 -or $_ -eq 5} {$App4,$App6,$App7|%{If(!($ToInstall -contains $_)){$ToInstall += $_}}}
        {!($_ -ieq "q")} {$ToInstall += $App5}
        {$_ -ieq "q"} {Write-host "Exiting!";Exit}
    }


# Install each app selected

ForEach($App in ($ToInstall |Sort Name)){
    Write-Host $App.Name
    if (Test-Path $App.Path) {
        If($App.Name -eq "App3 Title"){Do stuff to stop service}
        $processInfo = New-Object System.Diagnostics.ProcessStartInfo "msiexec.exe"
        $processInfo.arguments = $App.args
        $processMSI = New-Object System.Diagnostics.Process
        $processMSI.StartInfo = $processInfo
        $processMSI.Start() | Out-Null
        $processMSI.WaitforExit()

        if ($processMSI.ExitCode -ne 0) {
            Write-Host "The Installer generated error code:" $processMSI.ExitCode "Exiting!"
            exit
        }
    }
    Else {
        Write-host "Installer does not exist. Exiting!"
        exit
    }
}

编辑:将对象的创建移至切换之前,插入代码以检查指定应用程序安装上的服务。

修改2:更新了$processInfo.arguments =行,修正了$App3 - $App7行。还重新将应用程序添加到$ToInstall数组中,以避免在ForEach循环中重复和排序安装顺序。

答案 1 :(得分:0)

这是一个调用自身的函数,直到给出有效的响应。

Function Get-Response {
    Param ($Main_Prompt)
    switch (Read-Host $Main_Prompt) {
        1 {1}
        2 {2}
        3 {3}
        4 {4}
        5 {5}
        "q" {'q'}
        Default {Get-Response @PSBoundParameters}
    }
}

$Value = Get-Response -Main_Prompt 'Do Something'
Write-Verbose "Value: $Value given" -Verbose