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?


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

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
}

@ 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

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...
}

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.


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)


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.


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

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.


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

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
}

`` `


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)


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"

}
Ao utilizar nosso site, você reconhece que leu e compreendeu nossa Política de Cookies e nossa Política de Privacidade.
Licensed under cc by-sa 3.0 with attribution required.