¿Cómo verifico si está instalado un módulo de PowerShell?

92

Para comprobar si existe un módulo, he intentado lo siguiente:

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

La salida es:

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

Recibo un error, pero no se lanza ninguna excepción, por lo que vemos Module existsal final, aunque SomeModuleno existe.

¿Existe una buena manera (preferiblemente sin generar un error) para detectar si un módulo de PowerShell está instalado en el sistema?

Klemens Schindler
fuente

Respuestas:

119

Puede utilizar la ListAvailableopción de Get-Module:

if (Get-Module -ListAvailable -Name SomeModule) {
    Write-Host "Module exists"
} 
else {
    Write-Host "Module does not exist"
}
Klemens Schindler
fuente
1
Iba a sugerir: Import-Module NonexistingModule -ErrorAction SilentlyContinue IF ($ error) {Write-Host 'Module does not exist'} ELSE {Write-Host 'Module does exist'} Pero su camino es mejor, más elegante :)
Erik Blomgren
Esto funciona muy bien. Gracias. Usaré Write-Warning "Module does not exist..." ;BreakPero has hecho todo el trabajo duro.
Craig.C
Si está importando bibliotecas utilizando Import-Moduleun archivo dll personalizado, no use la -ListAvailableopción para determinar si el módulo está instalado porque no aparecerá en la lista. Según la documentación de PowerShell 6 , "ListAvailable no devuelve información sobre los módulos que no se encuentran en la variable de entorno PSModulePath, incluso si esos módulos se cargan en la sesión actual".
Dave F
Esto no determina si se ha instalado un módulo (es decir, Import-Module) solo determina si el módulo está disponible de inmediato para ser instalado sin especificar una ubicación específica que aún no se encuentra en$env:PSModulePath
Slogmeister Extraordinaire
35

La opción ListAvailable no me funciona. En cambio, esto hace:

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

O, para ser más sucinto:

if (!(Get-Module "<moduleNameHere>")) {
    # module is not loaded
}
karezza
fuente
@ oɔɯǝɹ Pensé que -ListAvailable simplemente no estaba disponible, pero todavía estaba probando Import-Module. Con Get-Module está bien
Craig.C
2
Verifica si el módulo está CARGADO (que es útil por sí mismo - systemcentercentral.com/… ), pero no la otra respuesta verifica si el módulo existe.
Michael Freidgeim
1
Esto se ejecuta mucho más rápido que usar ListAvailable.
GaTechThomas
¿Está bastante seguro de !que no funciona en PowerShell dependiendo de la versión?
Cañón Kolob
2
@KolobCanyon !es un alias de -not, pero no recomendaría usar alias en los scripts de ps1 en general. @GaTechThomas también tiene un comportamiento diferente, según lo especificado por @MichaelFreidgeim (no devuelve un valor verdadero para los módulos instalados, pero no importados).
AndreasHassing
27

Un módulo puede estar en los siguientes estados:

  • importado
  • disponible en disco (o red local)
  • disponible en la galería en línea

Si solo desea tener la maldita cosa disponible en una sesión de PowerShell para su uso, aquí hay una función que lo hará o saldrá si no puede hacerlo:

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
varilla
fuente
1
esta es una gran solución "todo en uno" (solo he cambiado Load-Module para que devuelva $ true / $ false en lugar de EXIT)
Andrzej Martyna
17

La versión actual de Powershell tiene una Get-InstalledModulefunción que se adapta bien a este propósito (o al menos lo hizo en mi caso).

Get-InstalledModule

Descripción

El Get-InstalledModulecmdlet obtiene los módulos de PowerShell que están instalados en una computadora.

El único problema con esto es que genera una excepción si el módulo que se solicita no existe, por lo que debemos configurarlo ErrorActionadecuadamente para suprimir ese caso.

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

    # Install it...
}
NightOwl888
fuente
13

Simplemente revisando esto, ya que es algo que acabo de enfrentar y hay algunas cosas incorrectas en las respuestas (aunque se menciona en los comentarios).

Aunque lo primero. Las preguntas originales preguntan cómo saber si un módulo de PowerShell está instalado. ¡Tenemos que hablar de la palabra instalada! No instala módulos de PowerShell (no de la forma tradicional en que instala el software de todos modos).

Los módulos de PowerShell están disponibles (es decir, están en la ruta del módulo de PowerShell) o se importan (se importan a su sesión y puede llamar a las funciones que contiene). Así es como verificar la ruta de su módulo, en caso de que quiera saber dónde almacenar un módulo:

$env:psmodulepath

Yo diría que se está volviendo común usar C: \ Archivos de programa \ WindowsPowerShell \ Modules; más a menudo debido a que está disponible para todos los usuarios, pero si desea bloquear sus módulos en su propia sesión, inclúyalos en su perfil.C: \ Users \% username% \ Documents \ WindowsPowerShell \ Modules;

Muy bien, volvamos a los dos estados.

¿Está disponible el módulo (usando disponible para significar instalado en la pregunta original)?

Get-Module -Listavailable -Name <modulename>

Esto le indica si un módulo está disponible para importar.

¿Se importa el módulo? (Estoy usando esto como la respuesta para la palabra 'existe' en la pregunta original).

Get-module -Name <modulename>

Esto devolverá una carga vacía de nada si el módulo no se importa, o una descripción de una línea del módulo si lo es. Como siempre en Stack Overflow, pruebe los comandos anteriores en sus propios módulos.

bytejunkie
fuente
1
Puede instalar el módulo en PowerShell. PowerShellGet tiene un comando Get-InstalledModuleque no devuelve el mismo resultado queGet-Module -ListAvailable
Igor
9

Cuando utilizo módulos no predeterminados en mis scripts, llamo a la función a continuación. Además del nombre del módulo, puede proporcionar una versión 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
        } 
    }
}

ejemplo de uso:

Install-ModuleIfNotInstalled 'CosmosDB' '2.1.3.528'

Por favor, avíseme si es útil (o no)

TJ Galama
fuente
4

Puede usar la #Requiresdeclaración (admite módulos de PowerShell 3.0).

La instrucción #Requires evita que se ejecute un script a menos que se cumplan los requisitos previos de la versión de PowerShell, los módulos, los complementos y el módulo y la versión del complemento.

Entonces, en la parte superior del script, simplemente agregue #Requires -Module <ModuleName>

Si los módulos necesarios no están en la sesión actual, PowerShell los importa.

Si los módulos no se pueden importar, PowerShell arroja un error de terminación.

Sheldonzy
fuente
3

En mi humilde opinión, hay una diferencia entre verificar si un módulo es:

1) instalado o 2) importado:

Para comprobar si está instalado:

Opción 1: Uso Get-Modulecon -ListAvailableparámetro:

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

Opción 2: Usar $errorobjeto:

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

Para comprobar si es importado:

Usando Get-Modulecon el -Nameparámetro (que puede omitir ya que es predeterminado de todos modos):

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
fuente
3
try {
    Import-Module SomeModule
    Write-Host "Module exists"
} 
catch {
    Write-Host "Module does not exist"
}

Cabe señalar que su cmdlet Import-Module no tiene un error de terminación, por lo tanto, la excepción no se detecta, por lo que, independientemente de cuál sea su declaración de captura, nunca devolverá la nueva declaración que ha escrito.

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

Desde arriba:

"Un error de terminación detiene la ejecución de una instrucción. Si PowerShell no maneja un error de terminación de alguna manera, PowerShell también deja de ejecutar la función o el script usando la canalización actual. En otros lenguajes, como C #, los errores de terminación se conocen como excepciones . Para obtener más información sobre errores, consulte about_Errors ".

Debería escribirse como:

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

Que devuelve:

nope

Y si realmente desea ser minucioso, debe agregar los otros cmdlets sugeridos Get-Module -ListAvailable -Namey Get-Module -Nameser más cauteloso antes de ejecutar otras funciones / cmdlets. Y si está instalado desde psgallery o en otro lugar, también puede ejecutar un Find-Modulecmdlet para ver si hay una nueva versión disponible.

mwtilton
fuente
2

Puedes usar el Get-InstalledModule

If (-not(Get-InstalledModule SomeModule -ErrorAction silentlycontinue)) {
  Write-Host "Module does not exist"
}
Else {
  Write-Host "Module exists"
}
thesagarreddy
fuente
Muchas buenas respuestas aquí, pero con este nuevo método simple, esta probablemente debería ser la nueva respuesta aceptada.
not2qubit
1
  • Primero prueba si el módulo está cargado
  • Luego importa

''

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
fuente
1

Procedente de Linux. Preferiría usar algo similar a grep, por lo tanto, uso Select-String. Entonces, incluso si alguien no está seguro del nombre completo del módulo. Pueden proporcionar las iniciales y determinar si el módulo existe o no.

Get-Module -ListAvailable -All | Select-String Module_Name(puede ser parte del nombre del módulo)

010 M
fuente
1

Aquí está el código para verificar si el módulo AZ está instalado o no:

$checkModule = "AZ"

$Installedmodules = Get-InstalledModule

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

    "$checkModule is installed "

}

else {

    "$checkModule is not installed"

}
Alkum
fuente