Como posso verificar se um módulo PowerShell está instalado?

97

Para verificar se existe um módulo, tentei o seguinte:

try {
    Import-Module SomeModule
    Write-Host "Module exists"
} 
catch {
    Write-Host "Module does not exist"
}

O resultado é:

Import-Module : The specified module 'SomeModule' was not loaded because no valid module file was found in any module directory.
At D:\keytalk\Software\Client\TestProjects\Export\test.ps1:2 char:5
+     Import-Module SomeModule
+     ~~~~~~~~~~~~~~~~~~~~~~~~
    + CategoryInfo          : ResourceUnavailable: (SomeModule:String) [Import-Module], FileNotFoundException
    + FullyQualifiedErrorId : Modules_ModuleNotFound,Microsoft.PowerShell.Commands.ImportModuleCommand

Module exists

Eu recebo um erro, mas nenhuma exceção é lançada, então vemos Module existsno final, embora SomeModulenão exista.

Existe uma boa maneira (de preferência sem gerar um erro) para detectar se um módulo PowerShell está instalado no sistema?

Klemens Schindler
fonte

Respostas:

126

Você pode usar a ListAvailableopção de Get-Module:

if (Get-Module -ListAvailable -Name SomeModule) {
    Write-Host "Module exists"
} 
else {
    Write-Host "Module does not exist"
}
Klemens Schindler
fonte
1
Eu ia sugerir: Import-Module NonexistingModule -ErrorAction SilentlyContinue IF ($ error) {Write-Host 'Module does not exist'} ELSE {Write-Host 'Module does exist'} Mas seu jeito é melhor, mais elegante :)
Erik Blomgren
Isso funciona muito bem. Obrigado. Vou usar Write-Warning "Module does not exist..." ;BreakMas você fez todo o trabalho duro.
Craig.C de
Se você estiver importando bibliotecas usando Import-Moduleum arquivo dll personalizado, não use a -ListAvailableopção para determinar se o módulo está instalado porque ele não será listado. De acordo com a documentação do PowerShell 6 , "ListAvailable não retorna informações sobre módulos que não são encontrados na variável de ambiente PSModulePath, mesmo se esses módulos forem carregados na sessão atual".
Dave F
Isso não determina se um módulo foi instalado (ou seja Import-Module), apenas determina se o módulo está imediatamente disponível para ser instalado sem especificar um local específico ainda não em$env:PSModulePath
Slogmeister Extraordinaire
34

A opção ListAvailable não funciona para mim. Em vez disso:

if (-not (Get-Module -Name "<moduleNameHere>")) {
    # module is not loaded
}

Ou, para ser mais sucinto:

if (!(Get-Module "<moduleNameHere>")) {
    # module is not loaded
}
Karezza
fonte
@ oɔɯǝɹ Achei que -ListAvailable simplesmente não estivesse disponível, mas ainda estava tentando o Import-Module. Com Get-Module está tudo bem
Craig.C
3
Você verifica se o módulo LOADED (que é útil por si só - systemcentercentral.com/… ), mas não a outra resposta verifica se o módulo existe.
Michael Freidgeim
1
Isso é executado muito mais rápido do que usar ListAvailable.
GaTechThomas de
Quase certo !que não funciona no PowerShell dependendo da versão?
Kolob Canyon de
2
@KolobCanyon !é um alias para -not, mas eu não recomendaria usar aliases em scripts ps1 em geral. @GaTechThomas também possui um comportamento diferente, conforme especificado por @MichaelFreidgeim (não retorna um valor verdadeiro para os módulos instalados, mas não importados).
AndreasHassing
28

Um módulo pode estar nos seguintes estados:

  • importado
  • disponível em disco (ou rede local)
  • disponível na galeria online

Se você apenas deseja ter o danado disponível em uma sessão do PowerShell para uso, aqui está uma função que fará isso ou sairá se não puder fazer isso:

function Load-Module ($m) {

    # If module is imported say that and do nothing
    if (Get-Module | Where-Object {$_.Name -eq $m}) {
        write-host "Module $m is already imported."
    }
    else {

        # If module is not imported, but available on disk then import
        if (Get-Module -ListAvailable | Where-Object {$_.Name -eq $m}) {
            Import-Module $m -Verbose
        }
        else {

            # If module is not imported, not available on disk, but is in online gallery then install and import
            if (Find-Module -Name $m | Where-Object {$_.Name -eq $m}) {
                Install-Module -Name $m -Force -Verbose -Scope CurrentUser
                Import-Module $m -Verbose
            }
            else {

                # If module is not imported, not available and not in online gallery then abort
                write-host "Module $m not imported, not available and not in online gallery, exiting."
                EXIT 1
            }
        }
    }
}

Load-Module "ModuleName" # Use "PoshRSJob" to test it out
Cajado
fonte
1
esta é uma ótima solução "tudo em um" (eu só alterei Load-Module para retornar $ true / $ false em vez de EXIT)
Andrzej Martyna
Isso é lindo.
sean
17

A versão atual do Powershell tem uma Get-InstalledModulefunção que se adapta bem a esse propósito (ou pelo menos no meu caso).

Get-InstalledModule

Descrição

O Get-InstalledModulecmdlet obtém módulos do PowerShell que são instalados em um computador.

O único problema com ele é que ele lança uma exceção se o módulo que está sendo solicitado não existir, portanto, precisamos definir ErrorActionadequadamente para suprimir esse caso.

if ((Get-InstalledModule `
    -Name "AzureRm.Profile" `
    -MinimumVersion 5.0 ` # Optionally specify minimum version to have
    -ErrorAction SilentlyContinue) -eq $null) {

    # Install it...
}
NightOwl888
fonte
13

Apenas revisitando isso, pois é algo que acabei de enfrentar e há algumas coisas incorretas nas respostas (embora sejam mencionadas nos comentários).

Mas a primeira coisa. As perguntas originais perguntam como saber se um módulo PowerShell está instalado. Precisamos falar sobre a palavra instalada! Você não instala módulos do PowerShell (não da maneira tradicional de instalar o software).

Os módulos do PowerShell estão disponíveis (ou seja, estão no caminho do módulo do PowerShell) ou são importados (são importados para a sua sessão e você pode chamar as funções contidas). Veja como verificar o caminho do módulo, caso você queira saber onde armazenar um módulo:

$env:psmodulepath

Eu diria que está se tornando comum usar C: \ Arquivos de Programas \ WindowsPowerShell \ Modules; mais frequentemente devido a estar disponível para todos os usuários, mas se você quiser bloquear seus módulos para sua própria sessão, inclua-os em seu perfil. C: \ Users \% username% \ Documents \ WindowsPowerShell \ Modules;

Tudo bem, de volta aos dois estados.

O módulo está disponível (usando disponível para significar instalado na questão original)?

Get-Module -Listavailable -Name <modulename>

Isso informa se um módulo está disponível para importação.

O módulo é importado? (Estou usando isso como a resposta para a palavra 'existe' na pergunta original).

Get-module -Name <modulename>

Isso retornará um carregamento vazio de nada se o módulo não for importado ou uma descrição de uma linha do módulo se for. Como sempre no Stack Overflow, tente os comandos acima em seus próprios módulos.

bytejunkie
fonte
1
Você pode instalar o módulo no PowerShell. PowerShellGet tem um comando Get-InstalledModuleque não está retornando a mesma saída queGet-Module -ListAvailable
Igor
9

Quando eu uso módulos não padrão em meus scripts, chamo a função abaixo. Ao lado do nome do módulo, você pode fornecer uma versão mínima.

# See https://www.powershellgallery.com/ for module and version info
Function Install-ModuleIfNotInstalled(
    [string] [Parameter(Mandatory = $true)] $moduleName,
    [string] $minimalVersion
) {
    $module = Get-Module -Name $moduleName -ListAvailable |`
        Where-Object { $null -eq $minimalVersion -or $minimalVersion -ge $_.Version } |`
        Select-Object -Last 1
    if ($null -ne $module) {
         Write-Verbose ('Module {0} (v{1}) is available.' -f $moduleName, $module.Version)
    }
    else {
        Import-Module -Name 'PowershellGet'
        $installedModule = Get-InstalledModule -Name $moduleName -ErrorAction SilentlyContinue
        if ($null -ne $installedModule) {
            Write-Verbose ('Module [{0}] (v {1}) is installed.' -f $moduleName, $installedModule.Version)
        }
        if ($null -eq $installedModule -or ($null -ne $minimalVersion -and $installedModule.Version -lt $minimalVersion)) {
            Write-Verbose ('Module {0} min.vers {1}: not installed; check if nuget v2.8.5.201 or later is installed.' -f $moduleName, $minimalVersion)
            #First check if package provider NuGet is installed. Incase an older version is installed the required version is installed explicitly
            if ((Get-PackageProvider -Name NuGet -Force).Version -lt '2.8.5.201') {
                Write-Warning ('Module {0} min.vers {1}: Install nuget!' -f $moduleName, $minimalVersion)
                Install-PackageProvider -Name NuGet -MinimumVersion 2.8.5.201 -Scope CurrentUser -Force
            }        
            $optionalArgs = New-Object -TypeName Hashtable
            if ($null -ne $minimalVersion) {
                $optionalArgs['RequiredVersion'] = $minimalVersion
            }  
            Write-Warning ('Install module {0} (version [{1}]) within scope of the current user.' -f $moduleName, $minimalVersion)
            Install-Module -Name $moduleName @optionalArgs -Scope CurrentUser -Force -Verbose
        } 
    }
}

exemplo de uso:

Install-ModuleIfNotInstalled 'CosmosDB' '2.1.3.528'

Por favor, deixe-me saber se é útil (ou não)

TJ Galama
fonte
4

Você pode usar a #Requiresinstrução (oferece suporte a módulos do PowerShell 3.0).

A instrução #Requires impede a execução de um script, a menos que a versão do PowerShell, os módulos, os snap-ins e os pré-requisitos de módulo e versão do snap-in sejam atendidos.

Portanto, no início do script, basta adicionar #Requires -Module <ModuleName>

Se os módulos necessários não estiverem na sessão atual, o PowerShell os importará.

Se os módulos não podem ser importados, o PowerShell lança um erro de encerramento.

Sheldonzy
fonte
3

IMHO, há diferença entre verificar se um módulo é:

1) instalado ou 2) importado:

Para verificar se instalado:

Opção 1: usando Get-Modulecom o -ListAvailableparâmetro:

If(Get-Module -ListAvailable -Name "<ModuleName>"){'Module is installed'}
Else{'Module is NOT installed'}

Opção 2: usando o $errorobjeto:

$error.clear()
Import-Module "<ModuleName>" -ErrorAction SilentlyContinue
If($error){Write-Host 'Module is NOT installed'}
Else{Write-Host 'Module is installed'}

Para verificar se importado:

Usando Get-Modulecom -Nameparâmetro (que você pode omitir, pois é o padrão de qualquer maneira):

if ((Get-Module -Name "<ModuleName>")) {
   Write-Host "Module is already imported (i.e. its cmdlets are available to be used.)"
}
else {
   Write-Warning "Module is NOT imported (must be installed before importing)."
}
Eddie Kumar
fonte
3
try {
    Import-Module SomeModule
    Write-Host "Module exists"
} 
catch {
    Write-Host "Module does not exist"
}

Deve-se observar que seu cmdlet Import-Modulenão tem erro de encerramento, portanto, a exceção não está sendo capturada, portanto, não importa qual seja sua instrução catch nunca retornará a nova instrução que você escreveu.

( https://docs.microsoft.com/en-us/powershell/module/microsoft.powershell.core/about/about_try_catch_finally?view=powershell-6

De cima:

"Um erro de finalização impede a execução de uma instrução. Se o PowerShell não manipular um erro de finalização de alguma forma, o PowerShell também interrompe a execução da função ou script usando o pipeline atual. Em outras linguagens, como C #, os erros de finalização são chamados de exceções . Para obter mais informações sobre erros, consulte about_Errors. "

Deve ser escrito como:

Try {
    Import-Module SomeModule -Force -Erroraction stop
    Write-Host "yep"
}
Catch {
    Write-Host "nope"
}

Que retorna:

nope

E se você realmente deseja ser completo, deve adicionar os outros cmdlets sugeridos Get-Module -ListAvailable -Namee Get-Module -Nameser extremamente cauteloso antes de executar outras funções / cmdlets. E se for instalado de psgallery ou de outro lugar, você também pode executar um Find-Modulecmdlet para ver se há uma nova versão disponível.

Mwtilton
fonte
3

Você pode usar o Get-InstalledModule

If (-not(Get-InstalledModule SomeModule -ErrorAction silentlycontinue)) {
  Write-Host "Module does not exist"
}
Else {
  Write-Host "Module exists"
}
thesagarreddy
fonte
Muitas respostas boas aqui, mas com este novo método simples, esta provavelmente deve ser a nova resposta aceita.
not2qubit
1
  • Primeiro teste se o módulo está carregado
  • Então importe

`` `

if (Get-Module -ListAvailable -Name <<MODULE_NAME>>) {
    Write-Verbose -Message "<<MODULE_NAME>> Module does not exist." -Verbose
}
if (!(Get-Module -Name <<MODULE_NAME>>)) {
    Get-Module -ListAvailable <<MODULE_NAME>> | Import-Module | Out-Null
}

`` `

Juliano Barbosa
fonte
1

Vindo de experiência em Linux. Eu preferiria usar algo semelhante ao grep, portanto, uso Select-String. Portanto, mesmo se alguém não tiver certeza do nome completo do módulo. Eles podem fornecer as iniciais e determinar se o módulo existe ou não.

Get-Module -ListAvailable -All | Select-String Module_Name(pode ser uma parte do nome do módulo)

010 mi
fonte
1

Aqui está o código para verificar se o módulo AZ está instalado ou não:

$checkModule = "AZ"

$Installedmodules = Get-InstalledModule

if ($Installedmodules.name -contains $checkModule)
{

    "$checkModule is installed "

}

else {

    "$checkModule is not installed"

}
Alkum
fonte