Get-Help cmdlet not working with implicit remoting - powershell

Summary:
I have several functions that are placed on a remote windows server built for implicit remoting. However, I am unable to utilize the Get-Help cmdlet to show the synopsis that I put into each of the functions that I created, so these are not native powershell cmdlets. The get-help cmdlet works fine with the scripts are running locally.
Question:
Is it not possible to use Get-Help with implicit remoting?
Edit 1.
Attempting Briantists fix
PS> $module = Import-Module 'tmp_2c0mhyix.ivb' -PSSession $sessVar -PassThru
Import-Module : Failure from remote command: Import-Module -Name 'tmp_2c0mhyix.ivb': The specified module 'tmp_2c0mhyix.ivb' was not loaded because no valid module file was found in any module directory.
At line:1 char:11
+ $module = Import-Module 'tmp_2c0mhyix.ivb' -PSSession $sessVar-Pa ...
+ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ CategoryInfo : ResourceUnavailable: (tmp_2c0mhyix.ivb:String) [Import-Module], FileNotFoundException
+ FullyQualifiedErrorId : Modules_ModuleNotFound,Microsoft.PowerShell.Commands.ImportModuleCommand
Tried this as well with out the module name as well.
PS> $module = Import-Module -PSSession $sessVar-PassThru
Import-Module : Parameter set cannot be resolved using the specified named parameters.
At line:1 char:11
+ $module = Import-Module -PSSession $sessVar-PassThru
+ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ CategoryInfo : InvalidArgument: (:) [Import-Module], ParameterBindingException
+ FullyQualifiedErrorId : AmbiguousParameterSet,Microsoft.PowerShell.Commands.ImportModuleCommand

Implicit remoting is a strange beast. It creates proxy functions in a temporary module, and it's the proxy functions that get called locally.
After you call Import-PSSession, call Get-Module and you'll see one with a weird tmp name.
Alternatively, you can import the module initially using this method $module = Import-Module -PSSession $mySession -PassThru to get the module returned in a variable.
Then you can call Get-Command -Module $module to see the functions, but check out the definition:
Get-Command -Module $module | Select-Object -First 1 -ExpandProperty Definition
Shay Levy goes into detail about proxy functions here, and you can see that they do include instructions for Get-Help so that it can find the right help topic, but when the command is on the other side of the remoting, I don't think those would work.
I don't know if I've ever tried using help for functions imported that way, so maybe it actually does work and it's just a bug you've found, but I feel like this info would still be helpful.

Related

Powershell Loading Binary Module

I have few powershell script which I am trying to put into module. In the same module I also intend to load a c# dll for token generation. DLL uses System.Management.Automation.
#content of asr.psm1
Import-Module ".\tokengenerator\PowershellTokenGenerator.dll"
Get-ChildItem $psscriptroot\*.ps1 -Recurse | ForEach-Object { . $_.FullName }
The folder tokengenerator includes dll to generate OAuth2.0 token. How can I load powershell module and C# cmdlet under the same module. However, when I am trying to load the module I get the below error.
Import-Module D:\repo\src\aadsr\setup\asr.psm1
Import-Module : The specified module '.\tokengenerator\PowershellTokenGenerator.dll' was not loaded because no valid module file was found in any module directory. At D:\repo\src\aadsr\setup\asr.psm1:1 char:1
+ Import-Module ".\tokengenerator\PowershellTokenGenerator.dll"
+ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ CategoryInfo : ResourceUnavailable: (.\tokengenerato...enGenerator.dll:String) [Import-Module], FileNotFoundException
+ FullyQualifiedErrorId : Modules_ModuleNotFound,Microsoft.PowerShell.Commands.ImportModuleCommand
Use:
Import-Module "$PSScriptRoot\tokengenerator\PowershellTokenGenerator.dll"
to ensure that the DLL is found relative to the script module's (*.psm1) location, reflected in automatic variable $PSScriptRoot.
By contrast, if you use Import-Module ".\...", the DLL is looked for relative to the current location (.), whatever it may be.

Powershell not always running ScriptsToProcess on import

After using Install-Module to install powershell-yaml I had about a week of use before I came in one morning to it not loading YamlDotNet properly.
Now if I try to use ConvertFrom-Yaml before manually running Import-Module powershell-yaml I get the the following error:
PS C:\Users\user> "---" | ConvertFrom-Yaml
New-Object : Cannot find type [YamlDotNet.RepresentationModel.YamlStream]: verify that the assembly containing this type is loaded.
At C:\Program Files\WindowsPowerShell\Modules\powershell-yaml\0.3.1\powershell-yaml.psm1:24 char:23
+ ... $yamlStream = New-Object "YamlDotNet.RepresentationModel.YamlStream"
+ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ CategoryInfo : InvalidType: (:) [New-Object], PSArgumentException
+ FullyQualifiedErrorId : TypeNotFound,Microsoft.PowerShell.Commands.NewObjectCommand
You cannot call a method on a null-valued expression.
At C:\Program Files\WindowsPowerShell\Modules\powershell-yaml\0.3.1\powershell-yaml.psm1:25 char:9
+ $yamlStream.Load([System.IO.TextReader] $stringReader)
+ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ CategoryInfo : InvalidOperation: (:) [], RuntimeException
+ FullyQualifiedErrorId : InvokeMethodOnNull
Previously (and on most systems) this worked fine. If I run a manual Import-Module before calling the function it works fine:
PS C:\Users\user> Import-Module powershell-yaml
PS C:\Users\user> "---" | ConvertFrom-Yaml
PS C:\Users\user>
Both my and a coworker's machines started this behavior at about the same time. This morning my system started working properly again, but his is still exhibiting the behavior. We haven't been able to duplicate it on other machines.
I've narrowed it down to a script referenced in Powershell-Yaml manifest's ScriptsToProcess not being called during autoload, but runs fine during a manual Import-Module. On working machines the script in ScriptsToProcess is run in both cases. As a workaround we can force a module load by putting an Import-Module in our profile, ideally we'd like to find a root cause.
Import-Module -Verbose doesn't help, because calling Import-Module first always works.

Does #Requires work in module scripts?

Consider the following module script:
MyWebApp.psm1:
#Requires -Version 4
#Requires -Modules WebAdministration
function Test-MyWebApp() {
return ((Get-WebApplication 'myapp') -ne $null)
}
(Export-ModuleMember omitted for simplicity. The script still works as a module without it.)
If this were a ps1 script, the #Requires comments at the top would force PowerShell to throw an error if
The version were lower than 4
The WebAdministration module could not be loaded (imported)
But if I try to import this using Import-Module, do these have any effect? The #Requires documentation just says "scripts", but it doesn't clarify whether script modules count as "scripts" or not here. What can I do instead, if not?
No, it's treated as a normal comment
No, #Requires comments are not processed when a psm1 script is executed by calling Import-Module.
If we save the script in the question as both MyWebApp.psm1 and MyWebApp.ps1 on a machine that lacks the WebAdministration module, we get the following result:
PS> .\MyWebApp.ps1
.\MyWebApp.ps1 : The script 'MyWebApp.ps1' cannot be run because the following modules that are specified by the
"#requires" statements of the script are missing: WebAdministration.
At line:1 char:1
+ .\MyWebApp.ps1
+ ~~~~~~~~~~~~~~
+ CategoryInfo : ResourceUnavailable: (MyWebApp.ps1:String) [], ScriptRequiresException
+ FullyQualifiedErrorId : ScriptRequiresMissingModules
PS> Import-Module .\MyWebApp.psm1
PS>
Importing the module succeeds, and the function now exists in the current scope. But the function will fail:
PS> Test-MyWebApp
Get-WebApplication : The term 'Get-WebApplication' is not recognized as the name of a cmdlet, function, script file,
or operable program. Check the spelling of the name, or if a path was included, verify that the path is correct and
try again.
At .\MyWebApp.psm1:5 char:14
+ return ((Get-WebApplication 'myapp') -Eq $null)
+ ~~~~~~~~~~~~~~~~~~
+ CategoryInfo : ObjectNotFound: (Get-WebApplication:String) [], CommandNotFoundException
+ FullyQualifiedErrorId : CommandNotFoundException
Even the -Version check is ignored. If we bump it up to 5 on a machine with only PowerShell 4:
PS> .\MyWebApp.ps1
.\MyWebApp.ps1 : The script 'MyWebApp.ps1' cannot be run because it contained a "#requires" statement for Windows
PowerShell 5.0. The version of Windows PowerShell that is required by the script does not match the currently running
version of Windows PowerShell 4.0.
At line:1 char:1
+ .\MyWebApp.ps1
+ ~~~~~~~~~~~~~~
+ CategoryInfo : ResourceUnavailable: (MyWebApp.ps1:String) [], ScriptRequiresException
+ FullyQualifiedErrorId : ScriptRequiresUnmatchedPSVersion
PS> Import-Module .\MyWebApp.psm1
PS>
Use a Module Manifest
The only way to get the requirements validated properly is to use a module manifest. Unfortunately, this must be a separate file alongside the psm1 file. The following manifest will achieve what the #Requires comments are intended to do:
MyWebApp.psd1:
#
# Module manifest for module 'MyWebApp'
#
#{
ModuleVersion = '1.0'
PowerShellVersion = '4.0'
RequiredModules = #('WebAdministration')
RootModule = #('.\MyWebApp.psm1')
}
Importing this file gives the error we want:
PS> Import-Module .\MyWebApp.psd1
Import-Module : The required module 'WebAdministration' is not loaded. Load the module or remove the module from 'RequiredModules' in the file
'.\MyWebApp.psd1'.
At line:1 char:1
+ Import-Module .\MyWebApp.psd1
+ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ CategoryInfo : ResourceUnavailable: (.\MyWebApp.psd1:String) [Import-Module], MissingMemberException
+ FullyQualifiedErrorId : Modules_InvalidManifest,Microsoft.PowerShell.Commands.ImportModuleCommand
Unfortunately, you cannot declare the function in the same file. You must use a separate psd1 file and then explicitly declare the original psm1 script as the "root module." The root module is indicated as a path relative to the psd1 file.
Other attributes:
The ModuleVersion is required. It must be present.
PowerShellVersion accomplishes what #Requires -Version 4 intends.
RequiredModules accomplishes what #Requires -Modules WebAdministration intends.
Note that Test-MyWebApp is exported implicitly in both the psm1 and the psd1 file. This is normally controlled by Export-ModuleMember -Function in a psm1 file; the equivalent in a module manifest is FunctionsToExport. I find it simpler to just omit FunctionsToExport from the manifest and control what's exported using Export-ModuleMember in the psm1 script.

How to install documentation for 7zip4PowerShell

After installing the 7zip4PowerShell module, if I call Get-Help on any of its cmdlets, I get the message
Get-Help cannot find the Help files for this cmdlet on this computer. It is displaying only partial help.
-- To download and install Help files for the module that includes this cmdlet, use Update-Help.
If I call update-help by itself, it doesn't change anything.
If I call update-help -Module 7zip4PowerShell, I get the following:
PS C:\windows\system32> update-help -Module 7zip4PowerShell
update-help : Failed to update Help for the module(s) :
'7Zip4Powershell'
The HelpInfoURI https://github.com/thoemmi/7Zip4Powershell does not start with HTTP.
At line:1 char:1
+ update-help -Module 7zip4PowerShell
+ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ CategoryInfo : NotSpecified: (HelpInfoUri:Uri) [Update-Help], Exception
+ FullyQualifiedErrorId : InvalidHelpInfoUriFormat,Microsoft.PowerShell.Commands.UpdateHelpCommand
What am I doing wrong?

Where is the best place to Add-PSSnapin SqlServerCmdletSnapin* and SqlServerProviderSnapin*?

I created some psm1 files and I put the following lines at the top of every psm1 file,
Set-StrictMode -Version 2
Add-PSSnapin SqlServerCmdletSnapin*
Add-PSSnapin SqlServerProviderSnapin*
However, it got warning of
WARNING: The names of some imported commands from the module 'mymodule' include unapproved verbs that might make them
less discoverable. To find the commands with unapproved verbs, run the Import-Module command again with the Verbose
parameter. For a list of approved verbs, type Get-Verb.
And it got the following error if import the modules multiple times.
Add-PSSnapin : An item with the same key has already been added.
At line:1 char:1
+ Add-PSSnapin SqlServerCmdletSnapin*
+ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ CategoryInfo : NotSpecified: (:) [Add-PSSnapin], ArgumentException
+ FullyQualifiedErrorId : System.ArgumentException,Microsoft.PowerShell.Commands.AddPSSnapinCommand
Add-PSSnapin : An item with the same key has already been added.
At line:2 char:1
+ Add-PSSnapin SqlServerProviderSnapin*
+ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ CategoryInfo : NotSpecified: (:) [Add-PSSnapin], ArgumentException
+ FullyQualifiedErrorId : System.ArgumentException,Microsoft.PowerShell.Commands.AddPSSnapinCommand
Or is there a way make these snapins loaded for every users when the system is booted?
The warning simply says that authors of SqlServerCmdletSnapin and SqlServerProviderSnapin used some 'unapproved' names for their functions. But these functions will work just fine, though MS thinks they can be 'less discoverable' (when user search commands like writing "Get-" and pressing Tab-Tab-Tab... from PS console).
So you are right to put them on the top, just add -ErrorAction SilentlyContinue to get rid of the warning:
Add-PSSnapin SqlServerCmdletSnapin* -ErrorAction SilentlyContinue
Add-PSSnapin SqlServerProviderSnapin* -ErrorAction SilentlyContinue
As for loading these snapins for every user, there are several options to do that using profiles. Read Understanding the Six PowerShell Profiles article.