Script Powershell para procurar e instalar o software, se não estiver presente

0

Estou tentando escrever um script PowerShell que procure por determinados programas e, se não encontrá-los, instale-os. Eu estou usando chocolate para fazer isso e parece funcionar muito bem. Aqui está o que eu tenho até agora:

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")

Então eu tenho 2 problemas. A primeira é que tudo após o primeiro "write-host" é exibido. Eu sei que posso ocultar a janela, mas não quero fazer isso com o objetivo de testar e depurar meu código. Eu tentei encapsular todos os comandos do host de gravação com {} mas ele ainda mostrava todo o código, como em quando o script é executado, vejo todos os comandos mostrados na janela do PS. Se este fosse o lote, eu apenas desligaria @echo mas não sei como fazer isso em powershell.

O segundo problema é que é confuso. Isso funciona, mas é confuso. Eu sinto que eu deveria ser capaz de condensar esse código, não sei como. Neste caso, eu preciso iterar sobre cada "App" e, em seguida, instale um programa diferente se esse "App" específico não for encontrado no sistema. Então, ele procura pelo google earth, e se ele não o encontrar, ele executa o comando para instalá-lo ... em seguida, faz um loop para o próximo aplicativo ... não o encontra e executa um comando diferente para instalar aquele e assim por diante. Eu bati uma parede com este embora. Eu tenho procurado por loops e arrays para tentar ver se eu poderia encontrar uma maneira melhor de fazer isso, além de listar cada comando mais e mais como eu estou aqui, mas parece que para loops e for-each loops são significados para fazer a mesma coisa em cada elemento da matriz. Nesse caso, preciso que ele faça algo diferente, por exemplo, execute um comando diferente, ou não, com base no aplicativo que está procurando.

Qualquer dica ou conselho seria muito apreciado. Agradecemos antecipadamente.

    
por Mike Van Dunk 16.12.2017 / 03:53

1 resposta

0

1- Suspensórios encaracolados.

Existem muitos pares desnecessários deles. Confira a diferença que eles podem fazer:

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

As seções repetitivas if/else e Get-ItemProperty de seu código são sempre agrupadas em um par de chaves. Remova esses pares extras. Eles são a causa do seu código aparecer na saída do console. Parece que eles são o resultado de colar o conteúdo da função desde o início do script. Mais algumas informações sobre chaves / parênteses / parênteses: link

2- Isso é subjetivo.

Uma dica geral: melhore a consistência do recuo. O código de resolução de problemas pode ser difícil. Solução de problemas no código confuso é mais difícil. Facilite as coisas melhorando a legibilidade enquanto você escreve.

Por exemplo, as chaves extras do bloco de código que mencionei ao responder sua primeira pergunta poderiam ter sido mais facilmente identificadas se o recuo tivesse sido mantido de forma mais consistente.

O bloco original (redigido):

{
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\*'
    )
}
...
}

Desta vez com melhor recuo:

{
    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\*'
        )
    }
    ...
}

O maior fator que contribui para a confusão neste script é o uso repetido deste bloco de código. O script começa com uma função. Isso é ótimo, porque você estará chamando o conteúdo da função várias vezes. É para isso que servem as funções. No entanto, o conteúdo da função está sendo chamado repetidamente em todo o script. Não há necessidade de definir continuamente a variável $regpath e consultá-la com Get-ItemProperty . Isto é o que sua função faz. Remover esses blocos corta seu código pela metade.

Você está certo - loops e arrays ajudariam seu código de várias maneiras. Mantendo sua função, você pode percorrer cada aplicativo com algo assim:

# 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)
    }

}
    
por 16.12.2017 / 18:49