Public/Get-LocalModule.ps1
function Get-LocalModule { # .SYNOPSIS # Gets basic details of an Installed Psmodule # .DESCRIPTION # Its like using Get-InstalledModule but you can even find unregistered/"manually Installed" modules. (as long as they are in any of $env:PSModulePath folders) # .EXAMPLE # Get-LocalModule psake | Select-Object -ExpandProperty Path | Import-Module -Verbose [CmdletBinding()] [OutputType([LocalPsModule])] param ( # The name of the installed module to search on the machine. [Parameter(Mandatory = $true, Position = 0)] [ValidateNotNullOrEmpty()] [string]$Name, # The required module version. You don't use this parameter, # then this cmdlet will search for the highest version from the specified scope. [Parameter(Mandatory = $false, Position = 1)] [ValidateNotNullOrEmpty()] [version]$version, # If you don't use this parameter then, this cmdlet uses LocalMachine as a default scope. [Parameter(Mandatory = $false, Position = 2)] [ValidateSet('CurrentUser', 'LocalMachine')] [string]$Scope ) begin { $PsModule = $null class LocalPsModule { [string]$Name [string]$version [IO.FileInfo]$Psd1 [System.String]$Scope [IO.DirectoryInfo]$Path [bool]$Exists = $false [psobject]$Info = $null [bool]$IsReadOnly = $false [bool]$HasVersiondirs = $false LocalPsModule([string]$Name) { $ModuleBase = $null; $AvailModls = Get-Module -ListAvailable -Name $Name -ErrorAction Ignore if ($null -ne $AvailModls) { $ModuleBase = ($AvailModls.ModuleBase -as [string[]])[0] } if ($null -ne $ModuleBase) { $Module = $this::Find($Name, [IO.DirectoryInfo]::New($ModuleBase)) $this.IsReadOnly = $Module.IsReadOnly; $this.version = $Module.version; $this.Exists = $Module.Exists; $this.Scope = $Module.Scope $this.Path = $Module.Path $this.Psd1 = $Module.Psd1 $this.Name = $Module.Name $this.Info = $Module.Info } else { $this._Init_($Name, 'LocalMachine', $null) } } LocalPsModule([string]$Name, [string]$scope) { $this._Init_($Name, $scope, $null) } LocalPsModule([string]$Name, [version]$version) { $this._Init_($Name, $null, $version) } LocalPsModule([string]$Name, [string]$scope, [version]$version) { $this._Init_($Name, $scope, $version) } static hidden [PSCustomObject] Find([string]$Name) { [ValidateNotNullOrEmpty()][string]$Name = $Name $ModuleBase = $null; $AvailModls = Get-Module -ListAvailable -Name $Name -ErrorAction Ignore if ($null -ne $AvailModls) { $ModuleBase = ($AvailModls.ModuleBase -as [string[]])[0] } if ($null -ne $ModuleBase) { return [LocalPsModule]::Find($Name, [IO.DirectoryInfo]::New($ModuleBase)) } else { return [LocalPsModule]::Find($Name, 'LocalMachine', $null) } } static hidden [PSCustomObject] Find([string]$Name, [IO.DirectoryInfo]$ModuleBase) { [ValidateNotNullOrEmpty()][IO.DirectoryInfo]$ModuleBase = $ModuleBase $result = [PSCustomObject]@{ Name = [string]::Empty Path = $null Psd1 = $null Info = @{} scope = 'LocalMachine' Exists = $false Version = [version]::New() IsReadOnly = $false } $ModulePsd1 = ($ModuleBase.GetFiles().Where({ $_.Name -like "$Name*" -and $_.Extension -eq '.psd1' }))[0] if ($null -eq $ModulePsd1) { return $result } $result.Info = [LocalPsModule]::ReadPowershellDataFile($ModulePsd1.FullName) $result.Name = $ModulePsd1.BaseName $result.Psd1 = $ModulePsd1 $result.Path = if ($result.Psd1.Directory.Name -as [version] -is [version]) { $result.Psd1.Directory.Parent } else { $result.Psd1.Directory } $result.Exists = $ModulePsd1.Exists $result.Version = $result.Info.ModuleVersion -as [version] $result.IsReadOnly = $ModulePsd1.IsReadOnly return $result } static hidden [PSCustomObject] Find([string]$Name, [string]$scope, [version]$version) { $ModuleScope = $scope; if ([string]::IsNullOrWhiteSpace($ModuleScope)) { $ModuleScope = 'LocalMachine' } $Module = $null; $PsModule_Paths = $([LocalPsModule]::Get_Module_Paths($ModuleScope) | ForEach-Object { [IO.DirectoryInfo]::New("$_") } | Where-Object { $_.Exists } ).GetDirectories().Where({ $_.Name -eq $Name }); if ($PsModule_Paths.count -gt 0) { $Get_versionDir = [scriptblock]::Create('param([IO.DirectoryInfo[]]$direcrory) return ($direcrory | ForEach-Object { $_.GetDirectories() | Where-Object { $_.Name -as [version] -is [version] } })') $has_versionDir = $Get_versionDir.Invoke($PsModule_Paths).count -gt 0 $ModulePsdFiles = $PsModule_Paths | ForEach-Object { if ($has_versionDir) { [string]$MaxVersion = ($Get_versionDir.Invoke([IO.DirectoryInfo]::New("$_")) | Select-Object @{l = 'version'; e = { $_.BaseName -as [version] } } | Measure-Object -Property version -Maximum).Maximum [IO.FileInfo]::New([IO.Path]::Combine("$_", $MaxVersion, $_.BaseName + '.psd1')) } else { [IO.FileInfo]::New([IO.Path]::Combine("$_", $_.BaseName + '.psd1')) } } | Where-Object { $_.Exists } $Get_ModuleVersion = { param ([Parameter(Mandatory)][string]$Psd1Path) $data = [LocalPsModule]::ReadPowershellDataFile($Psd1Path) $_ver = $data.ModuleVersion; if ($null -eq $_ver) { $_ver = [version][IO.FileInfo]::New($Psd1Path).Directory.Name } return $_ver } $Req_ModulePsd1 = if ($null -eq $version) { $ModulePsdFiles | Sort-Object -Property version -Descending | Select-Object -First 1 } else { $ModulePsdFiles | Where-Object { $Get_ModuleVersion.Invoke($_.FullName) -eq $version } } $Module = [LocalPsModule]::Find($Req_ModulePsd1.Name, $Req_ModulePsd1.Directory) } return $Module } static [string[]] Get_Module_Paths() { return [LocalPsModule]::Get_Module_Paths($null) } static [string[]] Get_Module_Paths([string]$scope) { [string[]]$_Module_Paths = [System.Environment]::GetEnvironmentVariable('PSModulePath').Split([IO.Path]::PathSeparator) if ([string]::IsNullOrWhiteSpace($scope)) { return $_Module_Paths } [ValidateSet('CurrentUser', 'LocalMachine')][string]$scope = $scope if (!(Get-Variable -Name IsWindows -ErrorAction Ignore) -or $(Get-Variable IsWindows -ValueOnly)) { $psv = Get-Variable PSVersionTable -ValueOnly $allUsers_path = Join-Path -Path $env:ProgramFiles -ChildPath $(if ($psv.ContainsKey('PSEdition') -and $psv.PSEdition -eq 'Core') { 'PowerShell' } else { 'WindowsPowerShell' }) if ($Scope -eq 'CurrentUser') { $_Module_Paths = $_Module_Paths.Where({ $_ -notlike "*$($allUsers_path | Split-Path)*" -and $_ -notlike "*$env:SystemRoot*" }) } } else { $allUsers_path = Split-Path -Path ([System.Management.Automation.Platform]::SelectProductNameForDirectory('SHARED_MODULES')) -Parent if ($Scope -eq 'CurrentUser') { $_Module_Paths = $_Module_Paths.Where({ $_ -notlike "*$($allUsers_path | Split-Path)*" -and $_ -notlike "*/var/lib/*" }) } } return $_Module_Paths } static hidden [PSObject] ReadPowershellDataFile([string]$Psd1Path) { $null = Get-Item -Path $Psd1Path -ErrorAction Stop $data = New-Object PSObject; $text = [IO.File]::ReadAllText("$Psd1Path") $data = [scriptblock]::Create("$text").Invoke() return $data } hidden _Init_ ([string]$Name, [string]$scope, [version]$version) { [ValidateSet('CurrentUser', 'LocalMachine')][string]$scope = $scope $Module = [LocalPsModule]::Find($Name, $scope, $version); $this.IsReadOnly = $Module.IsReadOnly; $this.version = $Module.version; $this.Exists = $Module.Exists; $this.Scope = $Module.Scope $this.Path = $Module.Path $this.Psd1 = $Module.Psd1 $this.Name = $Module.Name $this.Info = $Module.Info } } } process { $PsModule = switch ($true) { $($PSBoundParameters.ContainsKey('version') -and $PSBoundParameters.ContainsKey('Scope')) { New-Object LocalPsModule($Name, $Scope, $version) ; break } $($PSBoundParameters.ContainsKey('version') -and !$PSBoundParameters.ContainsKey('Scope')) { New-Object LocalPsModule($Name, 'LocalMachine', $version) ; break } $(!$PSBoundParameters.ContainsKey('version') -and $PSBoundParameters.ContainsKey('Scope')) { New-Object LocalPsModule($Name, $Scope, $version) ; break } $(!$PSBoundParameters.ContainsKey('version') -and !$PSBoundParameters.ContainsKey('Scope')) { New-Object LocalPsModule($Name) ; break } Default { New-Object LocalPsModule($Name) } } } end { return $PsModule } } |