Я пытаюсь написать скрипт powershell, который ищет определенные программы и, если он не находит их, устанавливает их. Я использую шоколад, чтобы сделать это, и это, кажется, работает довольно хорошо. Вот что у меня так далеко:

if (!([Security.Principal.WindowsPrincipal] [Security.Principal.WindowsIdentity]::GetCurrent()).IsInRole([Security.Principal
.WindowsBuiltInRole] "Administrator")) { Start-Process powershell.exe "-NoProfile -ExecutionPolicy Bypass -File `"$PSCommandPath`"" -Verb RunAs; exit }

Set-ExecutionPolicy Bypass -Scope Process -Force; iex ((New-Object System.Net.WebClient).DownloadString('https://chocolatey.org/install.ps1'))

$tempdir = Get-Location
$tempdir = $tempdir.tostring()
$FirstAppToMatch = '*Google Earth*'
$SecondAppToMatch = '*Google Chrome*'
$ThirdAppToMatch = '*FireFox*'
$FourthAppToMatch = '*Notepad++*'
$FifthAppToMatch = '*Adobe Reader*'
$SixthAppToMatch = '*Office*'
$msiFile = $tempdir+"\microsoft.interopformsredist.msi"
$msiArgs = "-qb"

function Get-InstalledApps
{
if ([IntPtr]::Size -eq 4) {
    $regpath = 'HKLM:\Software\Microsoft\Windows\CurrentVersion\Uninstall\*'
}
else {
    $regpath = @(
        'HKLM:\Software\Microsoft\Windows\CurrentVersion\Uninstall\*'

'HKLM:\Software\Wow6432Node\Microsoft\Windows\CurrentVersion\Uninstall\*'
    )
}
Get-ItemProperty $regpath | .{process{if($_.DisplayName -and 
$_.UninstallString) { $_ } }} | Select DisplayName, Publisher, InstallDate, 
DisplayVersion, UninstallString |Sort DisplayName
}

$result = Get-InstalledApps | where {$_.DisplayName -like $FirstAppToMatch}

If ($result -eq $null) {
(cinst googleearthpro -y)
}

Write-Host "Press any key to continue ..."

$x = $host.UI.RawUI.ReadKey("NoEcho,IncludeKeyDown")

{
if ([IntPtr]::Size -eq 4) {
    $regpath = 'HKLM:\Software\Microsoft\Windows\CurrentVersion\Uninstall\*'
}
else {
$regpath = @(
        'HKLM:\Software\Microsoft\Windows\CurrentVersion\Uninstall\*'

'HKLM:\Software\Wow6432Node\Microsoft\Windows\CurrentVersion\Uninstall\*'
    )
}
Get-ItemProperty $regpath | .{process{if($_.DisplayName -and 
$_.UninstallString) { $_ } }} | Select DisplayName, Publisher, InstallDate, 
DisplayVersion, UninstallString |Sort DisplayName
}

$result = Get-InstalledApps | where {$_.DisplayName -like $SecondAppToMatch}

If ($result -eq $null) {
(cinst googlechrome -y)
}

Write-Host "Press any key to continue ..."

$x = $host.UI.RawUI.ReadKey("NoEcho,IncludeKeyDown")

{
if ([IntPtr]::Size -eq 4) {
    $regpath = 'HKLM:\Software\Microsoft\Windows\CurrentVersion\Uninstall\*'
}
else {
    $regpath = @(
        'HKLM:\Software\Microsoft\Windows\CurrentVersion\Uninstall\*'

'HKLM:\Software\Wow6432Node\Microsoft\Windows\CurrentVersion\Uninstall\*'
    )
}
Get-ItemProperty $regpath | .{process{if($_.DisplayName -and 
$_.UninstallString) { $_ } }} | Select DisplayName, Publisher, InstallDate, 
DisplayVersion, UninstallString |Sort DisplayName
}

$result = Get-InstalledApps | where {$_.DisplayName -like $ThirdAppToMatch}

If ($result -eq $null) {
(cinst firefox -y)
}

Write-Host "Press any key to continue ..."

$x = $host.UI.RawUI.ReadKey("NoEcho,IncludeKeyDown")

{
if ([IntPtr]::Size -eq 4) {
    $regpath = 'HKLM:\Software\Microsoft\Windows\CurrentVersion\Uninstall\*'
}
else {
    $regpath = @(
        'HKLM:\Software\Microsoft\Windows\CurrentVersion\Uninstall\*'

'HKLM:\Software\Wow6432Node\Microsoft\Windows\CurrentVersion\Uninstall\*'
    )
}
Get-ItemProperty $regpath | .{process{if($_.DisplayName -and 
$_.UninstallString) { $_ } }} | Select DisplayName, Publisher, InstallDate, 
DisplayVersion, UninstallString |Sort DisplayName
}

$result = Get-InstalledApps | where {$_.DisplayName -like $FourthAppToMatch}

If ($result -eq $null) {
(cinst notepadplus -y)
}

Write-Host "Press any key to continue ..."

$x = $host.UI.RawUI.ReadKey("NoEcho,IncludeKeyDown")

{
if ([IntPtr]::Size -eq 4) {
    $regpath = 'HKLM:\Software\Microsoft\Windows\CurrentVersion\Uninstall\*'
}
else {
    $regpath = @(
        'HKLM:\Software\Microsoft\Windows\CurrentVersion\Uninstall\*'

'HKLM:\Software\Wow6432Node\Microsoft\Windows\CurrentVersion\Uninstall\*'
    )
}
Get-ItemProperty $regpath | .{process{if($_.DisplayName -and 
$_.UninstallString) { $_ } }} | Select DisplayName, Publisher, InstallDate, 
DisplayVersion, UninstallString |Sort DisplayName
}

$result = Get-InstalledApps | where {$_.DisplayName -like $FifthAppToMatch}

If ($result -eq $null) {
(cinst adobereader -y)
}

Write-Host "Press any key to continue ..."

$x = $host.UI.RawUI.ReadKey("NoEcho,IncludeKeyDown")

{
if ([IntPtr]::Size -eq 4) {
    $regpath = 'HKLM:\Software\Microsoft\Windows\CurrentVersion\Uninstall\*'
}
else {
    $regpath = @(
        'HKLM:\Software\Microsoft\Windows\CurrentVersion\Uninstall\*'

'HKLM:\Software\Wow6432Node\Microsoft\Windows\CurrentVersion\Uninstall\*'
    )
}
Get-ItemProperty $regpath | .{process{if($_.DisplayName -and 
$_.UninstallString) { $_ } }} | Select DisplayName, Publisher, InstallDate, 
DisplayVersion, UninstallString |Sort DisplayName
}

$result = Get-InstalledApps | where {$_.DisplayName -like $SixthAppToMatch}

If ($result -eq $null) {
(cinst office365business -y)
}

Write-Host "Press any key to continue ..."

$x = $host.UI.RawUI.ReadKey("NoEcho,IncludeKeyDown")

Итак, у меня есть 2 вопроса. Во-первых, все после первого «write-host» отображается. Я знаю, что могу скрыть окно, но я не хочу делать это в целях тестирования и отладки своего кода. Я попытался инкапсулировать все команды write-host с помощью {}, но он по-прежнему отображал весь код, так как во время выполнения скрипта я вижу все команды, показанные в окне PS. Если бы это была партия, я бы просто отключил @echo, но я не уверен, как это сделать в powershell.

Вторая проблема - это грязно. Это работает, но это грязно. Я чувствую, что смогу немного сжать этот код, я просто не знаю как. В этом случае мне нужно перебрать каждое "приложение", а затем установить другую программу, если это конкретное "приложение" не найдено в системе. Таким образом, он ищет Google Планета Земля, и если он не находит его, он запускает команду для его установки ... затем он возвращается к следующему приложению ... не находит его и запускает другую команду для установки тот и так далее. Я ударил стену с этим, хотя. Я искал циклы и массивы, чтобы попытаться найти лучший способ сделать это, кроме перечисления каждой команды снова и снова, как я здесь, но кажется, что циклы for и for-each предназначены сделать то же самое с каждым элементом в массиве. В этом случае мне нужно сделать что-то другое, т.е. выполнить другую команду или нет, в зависимости от приложения, которое она ищет.

Любые советы или рекомендации будут с благодарностью. Заранее спасибо.

1 ответ1

0

1- фигурные скобки.

Есть много ненужных пар из них. Проверьте разницу, которую они могут сделать:

PS C:\> Write-Host "foo"
foo
PS C:\> {Write-Host "foo"}
Write-Host "foo"

Повторяющиеся секции вашего кода if/else и Get-ItemProperty всегда заключаются в пару фигурных скобок. Удалите эти лишние пары. Они являются причиной появления вашего кода в выводе консоли. Похоже, они являются результатом вставки содержимого функции с начала скрипта. Еще немного информации о скобках / скобках / скобках: http://www.powertheshell.com/scriptblock/

2- Это субъективно.

Общий совет: улучшите последовательность отступов. Код устранения неполадок может быть сложным. Устранить проблемы с грязным кодом сложнее. Делайте вещи проще, улучшая читабельность при написании.

Например, дополнительные скобки из блока кода, который я упомянул, отвечая на ваш первый вопрос, можно было бы легче определить, если бы отступы сохранялись более последовательно.

Исходный блок (отредактированный):

{
if ([IntPtr]::Size -eq 4) {
    $regpath = 'HKLM:\Software\Microsoft\Windows\CurrentVersion\Uninstall\*'
}
else {
    $regpath = @(
        'HKLM:\Software\Microsoft\Windows\CurrentVersion\Uninstall\*'

'HKLM:\Software\Wow6432Node\Microsoft\Windows\CurrentVersion\Uninstall\*'
    )
}
...
}

На этот раз с улучшенным отступом:

{
    if ([IntPtr]::Size -eq 4) {
        $regpath = 'HKLM:\Software\Microsoft\Windows\CurrentVersion\Uninstall\*'
    }
    else {
        $regpath = @(
            'HKLM:\Software\Microsoft\Windows\CurrentVersion\Uninstall\*'

            'HKLM:\Software\Wow6432Node\Microsoft\Windows\CurrentVersion\Uninstall\*'
        )
    }
    ...
}

Самым большим фактором, способствующим беспорядку в этом скрипте, является повторное использование этого блока кода. Сценарий начинается с функции. Это здорово, потому что вы будете вызывать содержимое функции много раз. Это то, для чего нужны функции. Тем не менее, содержимое функции неоднократно вызывается по всему сценарию. Нет необходимости постоянно устанавливать переменную $regpath и запрашивать ее с помощью Get-ItemProperty . Это то, что делает ваша функция. Удаление этих блоков разрезает ваш код пополам.

Вы правы - циклы и массивы могут помочь вашему коду во многих отношениях. Сохраняя свою функцию, вы можете перебирать каждое приложение примерно так:

# the index of each App matches the installer name
$apps = @('Google Earth','Google Chrome','FireFox','Notepad++','Adobe Reader','Office')
$name = @('googleearthpro','googlechrome','firefox','notepadplus','adobereader','office365business')

foreach($app in $apps) {

    $result = Get-InstalledApps | Where-Object { $_.DisplayName -like $app }

    if($result -eq $null) {

        # get the index for the installer for this app
        $i = $apps.IndexOf($app)
        Write-Host "$app not found. Installing" $name[$i]

        (cinst $name[$i] -y)
    }

}

Всё ещё ищете ответ? Посмотрите другие вопросы с метками .