Jak sprawdzić, czy jest zainstalowany moduł PowerShell?

92

Aby sprawdzić, czy moduł istnieje, próbowałem wykonać następujące czynności:

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

Wynik to:

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

Otrzymuję błąd, ale nie jest zgłaszany żaden wyjątek, więc widzimy Module existsna końcu, chociaż SomeModulenie istnieje.

Czy istnieje dobry sposób (najlepiej bez generowania błędu) na wykrycie, czy w systemie jest zainstalowany moduł PowerShell?

Klemens Schindler
źródło

Odpowiedzi:

119

Możesz skorzystać z ListAvailableopcji Get-Module:

if (Get-Module -ListAvailable -Name SomeModule) {
    Write-Host "Module exists"
} 
else {
    Write-Host "Module does not exist"
}
Klemens Schindler
źródło
1
Miałem zamiar zasugerować: Import-Module NonexistingModule -ErrorAction SilentlyContinue IF ($ error) {Write-Host 'Module not exist'} ELSE {Write-Host 'Module does'} Ale twoja droga jest lepsza, bardziej elegancka :)
Erik Blomgren
To działa świetnie. Dzięki. Użyję Write-Warning "Module does not exist..." ;BreakAle wykonałeś całą ciężką pracę.
Craig.C
Jeśli importujesz biblioteki przy użyciu Import-Modulei niestandardowego pliku dll, nie używaj -ListAvailableopcji określania, czy moduł jest zainstalowany, ponieważ nie ma go na liście. Zgodnie z dokumentacją programu PowerShell 6 „ListAvailable nie zwraca informacji o modułach, które nie zostały znalezione w zmiennej środowiskowej PSModulePath, nawet jeśli te moduły są ładowane w bieżącej sesji”.
Dave F
Nie określa to, czy moduł został zainstalowany (tj. Import-Module) Określa tylko, czy moduł jest natychmiast dostępny do zainstalowania bez określania konkretnej lokalizacji, której jeszcze nie ma$env:PSModulePath
Slogmeister Extraordinaire
35

Opcja ListAvailable nie działa dla mnie. Zamiast tego robi to:

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

Lub, aby być bardziej zwięzłym:

if (!(Get-Module "<moduleNameHere>")) {
    # module is not loaded
}
karezza
źródło
@ oɔɯǝɹ Myślałem, że -ListAvailable było po prostu niedostępne, ale nadal próbowałem Import-Module. Z Get-Module wszystko w porządku
Craig.C
2
Sprawdzasz, czy moduł ZAŁADOWANY (co jest przydatne sam w sobie - systemcentercentral.com/… ), ale nie druga odpowiedź sprawdza, czy moduł istnieje.
Michael Freidgeim,
1
Wykonuje się to znacznie szybciej niż użycie ListAvailable.
GaTechThomas
Na pewno !nie działa w PowerShell w zależności od wersji?
Kolob Canyon,
2
@KolobCanyon !to alias dla -not, ale generalnie nie polecałbym używania aliasów w skryptach ps1. @GaTechThomas ma również inne zachowanie, określone przez @MichaelFreidgeim (nie zwraca prawdziwej wartości dla zainstalowanych, ale nie zaimportowanych modułów).
AndreasHassing
27

Moduł może znajdować się w następujących stanach:

  • importowany
  • dostępne na dysku (lub w sieci lokalnej)
  • dostępne w galerii online

Jeśli chcesz po prostu mieć tę cholerną rzecz dostępną w sesji PowerShell do użytku, oto funkcja, która to zrobi lub wyjdzie, jeśli nie może tego zrobić:

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
Pręt
źródło
1
to świetne rozwiązanie typu „wszystko w jednym” (zmieniłem tylko moduł Load-Module tak, aby zwracał $ true / $ false zamiast EXIT)
Andrzej Martyna
17

Obecna wersja programu Powershell ma Get-InstalledModulefunkcję, która dobrze pasuje do tego celu (a przynajmniej tak było w moim przypadku).

Get-InstalledModule

Opis

Polecenie Get-InstalledModulecmdlet pobiera moduły programu PowerShell, które są instalowane na komputerze.

Jedynym problemem jest to, że zgłasza wyjątek, jeśli żądany moduł nie istnieje, więc musimy ErrorActionodpowiednio ustawić, aby pominąć ten przypadek.

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

    # Install it...
}
NightOwl888
źródło
13

Po prostu wracam do tego, ponieważ jest to coś, z czym właśnie się spotkałem, aw odpowiedziach jest trochę niepoprawnych rzeczy (chociaż jest to wspomniane w komentarzach).

Jednak pierwsza rzecz. Oryginalne pytania dotyczą sposobu sprawdzenia, czy moduł programu PowerShell jest zainstalowany. Musimy porozmawiać o słowie zainstalowanym! Nie instalujesz modułów PowerShell (i tak nie w tradycyjny sposób instalujesz oprogramowanie).

Moduły PowerShell są albo dostępne (tj. Znajdują się na ścieżce modułu PowerShell), albo są importowane (są importowane do sesji i można wywołać zawarte w nich funkcje). Oto jak sprawdzić ścieżkę do modułu, jeśli chcesz wiedzieć, gdzie przechowywać moduł:

$env:psmodulepath

Twierdzę, że powszechne jest używanie C: \ Program Files \ WindowsPowerShell \ Modules; częściej, ponieważ jest dostępny dla wszystkich użytkowników, ale jeśli chcesz zablokować moduły do ​​własnej sesji, uwzględnij je w swoim profilu. C: \ Users \% username% \ Documents \ WindowsPowerShell \ Modules;

W porządku, wracając do dwóch stanów.

Czy moduł jest dostępny (używając available to znaczy zainstalowanego w oryginalnym pytaniu)?

Get-Module -Listavailable -Name <modulename>

Dzięki temu dowiesz się, czy moduł jest dostępny do importu.

Czy moduł jest zaimportowany? (Używam tego jako odpowiedzi na słowo „istnieje” w pierwotnym pytaniu).

Get-module -Name <modulename>

Spowoduje to albo zwrócenie pustego obciążenia, jeśli moduł nie jest zaimportowany, lub jednowierszowego opisu modułu, jeśli jest. Jak zawsze w Stack Overflow, wypróbuj powyższe polecenia na swoich własnych modułach.

bytejunkie
źródło
1
Możesz zainstalować moduł w PowerShell. PowerShellGet ma polecenie, Get-InstalledModulektóre nie zwraca tego samego wyniku, coGet-Module -ListAvailable
Igor
9

Kiedy używam modułów innych niż domyślne w moich skryptach, wywołuję poniższą funkcję. Oprócz nazwy modułu możesz podać wersję minimalną.

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

przykład użycia:

Install-ModuleIfNotInstalled 'CosmosDB' '2.1.3.528'

Proszę, daj mi znać, czy jest to przydatne (czy nie)

TJ Galama
źródło
4

Możesz użyć #Requiresinstrukcji (obsługuje moduły z programu PowerShell 3.0).

Instrukcja #Requires uniemożliwia uruchomienie skryptu, chyba że spełniono wymagania wstępne dotyczące wersji programu PowerShell, modułów, przystawek oraz modułu i wersji przystawki.

Więc u góry skryptu po prostu dodaj #Requires -Module <ModuleName>

Jeśli wymagane moduły nie znajdują się w bieżącej sesji, program PowerShell zaimportuje je.

Jeśli nie można zaimportować modułów, program PowerShell zgłasza błąd kończący.

sheldonzy
źródło
3

IMHO, jest różnica między sprawdzeniem, czy moduł jest:

1) zainstalowane lub 2) zaimportowane:

Aby sprawdzić, czy jest zainstalowany:

Opcja 1: Używanie Get-Modulez -ListAvailableparametrem:

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

Opcja 2: Korzystanie z $errorobiektu:

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

Aby sprawdzić, czy zaimportowano:

Używanie Get-Modulez -Nameparametrem (który możesz pominąć, ponieważ i tak jest domyślny ):

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
źródło
3
try {
    Import-Module SomeModule
    Write-Host "Module exists"
} 
catch {
    Write-Host "Module does not exist"
}

Należy zauważyć, że Twoje polecenie cmdlet Import-Modulenie ma błędu kończącego, dlatego wyjątek nie jest przechwytywany, więc bez względu na to, jaka instrukcja catch nigdy nie zwróci nowej instrukcji, którą napisałeś.

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

Z góry:

„Błąd zakończenia powoduje zatrzymanie wykonania instrukcji. Jeśli program PowerShell w jakiś sposób nie obsługuje błędu zakończenia, program PowerShell również zatrzymuje uruchamianie funkcji lub skryptu przy użyciu bieżącego potoku. W innych językach, takich jak C #, błędy kończące są nazywane wyjątkami . Aby uzyskać więcej informacji o błędach, zobacz about_Errors. "

Powinien być zapisany jako:

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

Który zwraca:

nope

A jeśli naprawdę chcesz być dokładny, powinieneś dodać inne sugerowane polecenia cmdlet Get-Module -ListAvailable -Namei Get-Module -Namezachować szczególną ostrożność, zanim uruchomisz inne funkcje / polecenia cmdlet. A jeśli jest zainstalowany z psgallery lub gdzie indziej, możesz również uruchomić polecenie Find-Modulecmdlet, aby sprawdzić, czy jest dostępna nowa wersja.

mwtilton
źródło
2

Możesz użyć Get-InstalledModule

If (-not(Get-InstalledModule SomeModule -ErrorAction silentlycontinue)) {
  Write-Host "Module does not exist"
}
Else {
  Write-Host "Module exists"
}
thesagarreddy
źródło
Wiele dobrych odpowiedzi tutaj, ale dzięki tej nowej prostej metodzie prawdopodobnie powinna to być nowa zaakceptowana odpowiedź.
not2qubit
1
  • Najpierw sprawdź, czy moduł jest załadowany
  • Następnie importuj

`` ''

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
źródło
1

Pochodzący z Linuksa. Wolałbym użyć czegoś podobnego do grep, dlatego używam Select-String. Więc nawet jeśli ktoś nie jest pewien pełnej nazwy modułu. Mogą podać inicjały i określić, czy moduł istnieje, czy nie.

Get-Module -ListAvailable -All | Select-String Module_Name(może być częścią nazwy modułu)

010 M
źródło
1

Oto kod, aby sprawdzić, czy moduł AZ jest zainstalowany, czy nie:

$checkModule = "AZ"

$Installedmodules = Get-InstalledModule

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

    "$checkModule is installed "

}

else {

    "$checkModule is not installed"

}
Alkum
źródło