PowerShell is fun :)Report from which PowerShell module the cmdlets are from (2024)

We all encountered this: you get a script or function that uses a certain cmdlet… And it fails because the cmdlet is not recognized 🙁 But which module should you install to get the script working? Or does your script install or import all the required modules? In this blog post, I will show you how to check from which module(s) the cmdlet(s) originate and if they are present on your system or if you should install them.

Table Of Contents

show

  • What are cmdlets?
  • How does the Function work?
  • Parameters that can be used
  • Examples
    • Using -Clipboard
    • Using -Cmdlets
    • Using -Scriptfile
    • Using -Outputfile
  • Wrapping up
  • The script

What are cmdlets?

“A cmdlet is a lightweight command that is used in the PowerShell environment. The PowerShell runtime invokes these cmdlets within the context of automation scripts that are provided at the command line. The PowerShell runtime also invokes them programmatically through PowerShell APIs.”

Examples are Get-Childitem, Get-Service, Write-Host, etc.

Source: https://learn.microsoft.com/en-us/powershell/scripting/developer/cmdlet/cmdlet-overview?view=powershell-7.4

How does the Function work?

I have created a Resolve-CmdletsToModules function to check the scripts I write or scripts/snippets I find on the internet and which module I must install to run the script correctly. The Function will parse all the lines in the script that you specify, the contents of your clipboard (For easy testing without having to save the script/snippet to a file first), or from one or more typed cmdlets and check that against a table of approved verbs to identity them. (Approved verbs start with Add-, Get-, Connect- etc.; more information about that here.)

The Function then checks every cmdlet from that list against your locally installed PowerShell Modules. If it finds the cmdlet there, it will report it back from which Module it can be loaded, including the version, if the Module is installed within the script/function/snippet, and if it is imported or not (Note: Not all modules require that)

If the cmdlet is not from a locally installed Module, the Function will check the cmdlet against the PSGallery and return all modules in which the cmdlet is present.

You can save the results to a .csv or .xlsx file, or it will output the results on your screen.

Parameters that can be used

The Function has four Parameters that you can use:

  • Clipboard: This will check the contents of your clipboard for cmdlets and report on them. It can be combined with Outputfile only.
  • -Cmdlets: This will check the cmdlets you specify separated by a comma. For example, -Cmdlets Connect-ExchangeOnline, Get-Mailbox.” It can be combined with -Outputfile only.
  • -Scriptfile: This will check the contents of the .ps1 script you specify, for example, “-ScriptFile c: scripts365Health.ps1.” It can be combined with -Outputfile only.
  • -Outputfile: You can specify the file to save the report. For example: “-Outputfile c:\temp\cmdlets.xlsx“. The filename has to end with either “.csv” or “.xlsx.” This can be combined with either -Clipboard, -Cmdlets, or -Scriptfile.

Examples

Below are a few examples of how the Function works:

Using -Clipboard

In the example below, I selected a snippet from a webpage to connect to Exchange Online and copied that to my clipboard. (“Connect-ExchangeOnline -UserPrincipalName john@contoso.com -ShowBanner:$false”)

Resolve-CmdletsToModules -clipboard

You can copy small or large parts of a script from anywhere, copy it to your clipboard, and run the Function with the -Clipboard parameter to report on that.

Using -Cmdlets

In the example below, I used the -Cmdlets parameter to let the Function check for Connect-ExchangeOnline and Connect-VIserver. The first is from a locally installed module, ExchangeOnlineManagement, but the second is from the VMware module VMware.VimAutomation.Core, which I didn’t install locally, and it will search for that online.

Resolve-CmdletsToModules -cmdlets Connect-ExchangeOnline, Connect-VIserver

You can see in the Location column that it found one local module and one from PSGallery. If the Function finds one from PSGallery, you should use Install-Module with the Module name to install it on your system so that you can use the specified cmdlet.

Using -Scriptfile

You can use the -Scriptfile parameter to specify a script the Function should check and report on. In the example below, I used the Function to check the script from one of my recent blogs.

Resolve-CmdletsToModules -scriptfile .\Convert-DTSLog.ps1

You can see that it checks the location of the specified script, the cmdlets in it, and the function name that it can’t resolve from the script itself. It reports Yes in both the installed and imported columns on the right because I specified that in the script as a check for the ImportExcel module.

Using -Outputfile

For all three parameters (-Clipboard, -Cmdlets, and -Scriptfile), you can use -Outputfile to save the results to a file instead of showing them on screen. In the example below, I created an Excel file based on the results of the script check from the chapter above.

Resolve-CmdletsToModules -scriptfile .\Convert-DTSLog.ps1 -outputfile c:\temp\convert-dtslog.xlsx

The Excel file looks like this:

Wrapping up

In the chapters above, I showed you how to use the script using the different parameters; it will help you fix scripts you can’t run because of missing modules on your system. Or to check your script so that you can include the install-module/import-module commands to help other people run your script on their system without them asking you why it doesn’t work 😉

The script

Below is the script’s contents. Save it to a file and use “. c:\scripts\Resolve-CmdletsToModules.ps1” to load the Function into your session. Or add it to your PowerShell profile by following these steps:

- notepad $profile- Add ". c:\scripts\Resolve-CmdletsToModules.ps1"- Close/Save- Start new PowerShell session- Use Resolve-CmdletsToModules with the parameters as specified above- Profit

Content of the script:

function Resolve-CmdletsToModules { param( [parameter(Mandatory = $true, parameterSetname = "Clipboard")][switch]$clipboard, [parameter(Mandatory = $true, parameterSetname = "Cmdlets")][string[]]$cmdlets, [parameter(Mandatory = $true, parameterSetname = "File")][string]$scriptfile, [parameter(Mandatory = $false)][string]$outputfile ) #Exit if incorrect extension was used if ($outputfile) { if (($outputfile.EndsWith('.csv') -ne $true) -and ($outputfile.EndsWith('.xlsx') -ne $true)) { Write-Warning ("Specified file {0} does not have the .csv or .xlsx extension. Exiting..." -f $outputfile) return } } #Check if Clipboard parameter was used and read contents of file in $scriptcontents if ($clipboard) { try { $scriptcontents = Get-Clipboard -ErrorAction Stop if ($scriptcontents.Length -gt 0) { write-host ("The Clipboard content is valid, continuing...") -ForegroundColor Green } else { Write-Warning ("Could not read Clipboard contents correctly, picture in Clipboard perhaps? Exiting...") return } } catch { Write-Warning ("Could not read Clipboard contents correctly, picture in Clipboard perhaps? Exiting...") return } } #Add values from $cmdlets to $scriptcontents if ($cmdlets) { $scriptcontents = $cmdlets } #Check if specified file is correct and read contents of file in $scriptcontents if ($scriptfile) { if (Test-Path -Path $scriptfile) { write-host ("The specified file {0} is valid, continuing..." -f $scriptfile) -ForegroundColor Green $scriptcontents = Get-Content -Path $scriptfile } else { Write-Warning ("The specified file {0} is invalid, exiting..." -f $scriptfile) return } } #$Verbs variable with valid PowerShell verbs to search for #https://learn.microsoft.com/en-us/powershell/scripting/developer/cmdlet/approved-verbs-for-windows-powershell-commands?view=powershell-7.4 #Add your own if needed. $verbs = @( "Add-" "Approve-" "Assert-" "Backup-" "Block-" "Build-" "Checkpoint-" "Clear-" "Close-" "Compare-" "Complete-" "Compress-" "Confirm-" "Connect-" "Convert-" "ConvertFrom-" "ConvertTo-" "Copy-" "Debug-" "Deny-" "Deploy-" "Disable-" "Disconnect-" "Dismount-" "Edit-" "Enable-" "Enter-" "Exit-" "Expand-" "Export-" "Find-" "Format-" "Get-" "Grant-" "Group-" "Hide-" "Import-" "Initialize-" "Install-" "Invoke-" "Join-" "Limit-" "Lock-" "Measure-" "Merge-" "Mount-" "Move-" "New-" "Open-" "Optimize-" "Out-" "Ping-" "Pop-" "Protect-" "Publish-" "Push-" "Read-" "Receive-" "Redo-" "Register-" "Remove-" "Rename-" "Repair-" "Request-" "Reset-" "Resize-" "Resolve-" "Restart-" "Restore-" "Resume-" "Revoke-" "Save-" "Search-" "Select-" "Send-" "Set-" "Show-" "Skip-" "Split-" "Start-" "Step-" "Stop-" "Submit-" "Suspend-" "Switch-" "Sync-" "Test-" "Trace-" "Unblock-" "Undo-" "Uninstall-" "Unlock-" "Unprotect-" "Unpublish-" "Unregister-" "Update-" "Use-" "Wait-" "Watch-" "Write-" ) #loop through each line in the script and get all the cmdlets being used #that are based on the approved verbs above $cmdletstocheck = foreach ($line in $scriptcontents) { if (-not $line.StartsWith('#')) { foreach ($word in $line.Split(' ')) { foreach ($verb in $verbs) { if ($word.ToLower().StartsWith($verb.ToLower())) { [PSCustomObject]@{ Cmdlet = $word -Replace '[\{\}\(\)\\]', '' } } } } } } #Search for the module(s) that the cmdlet is from $results = foreach ($cmdlet in ($cmdletstocheck | Sort-Object -Property * -Unique).Cmdlet | Sort-Object) { try { $cmdletinfo = Get-Command -Name $cmdlet -Erroraction Stop Write-Host ("Checking {0} locally" -f $cmdlet) -ForegroundColor Green foreach ($info in $cmdletinfo) { [PSCustomObject]@{ CmdletName = $info.Name CommandType = $info.CommandType ModuleName = $info.ModuleName Version = $info.Version Location = "Local" 'Is required module installed by script?' = if (($scriptcontents | Select-String $info.ModuleName | Select-String Install-Module) -or ($scriptcontents | Select-String $info.ModuleName | Select-String Install-PSResource)) { "Yes" } else { "No (Or -Cmdlets parameter was used)" } 'Is required module imported by script?' = if ($scriptcontents | Select-String $info.ModuleName | Select-String Import-Module) { "Yes" } else { "No (Or -Cmdlets parameter was used)" } } } } catch { Write-Warning ("Could not find information for {0} in your local modules, trying online..." -f $cmdlet) $cmdletinfo = Find-Module -Command $cmdlet Write-Host ("Checking {0} online" -f $cmdlet) -ForegroundColor Green if ($cmdletinfo) { foreach ($info in $cmdletinfo) { [PSCustomObject]@{ CmdletName = $cmdlet CommandType = $info.Type ModuleName = $info.Name Version = $info.Version Location = "PSGallery" 'Is required module installed by script?' = if (($scriptcontents | Select-String $info.Name | Select-String Install-Module) -or ($scriptcontents | Select-String $info.Name | Select-String Install-PSResource)) { "Yes" } else { "No (Or -Cmdlets parameter was used)" } 'Is required module imported by script?' = if ($scriptcontents | Select-String $info.Name | Select-String Import-Module) { "Yes" } else { "No (Or -Cmdlets parameter was used)" } } } } else { Write-Warning ("Could not find information for {0} in PSGallery, skipping..." -f $cmdlet) } } } #Output to .csv file if ($outputfile.EndsWith('.csv')) { if ($results) { try { New-Item -Path $outputfile -ItemType File -Force:$true -Confirm:$false -ErrorAction Stop | Out-Null $results | Sort-Object Name | Export-Csv -Path $outputfile -Encoding UTF8 -Delimiter ';' -NoTypeInformation Write-Host ("`nExported results to {0}" -f $outputfile) -ForegroundColor Green } catch { Write-Warning ("`nCould not export results to {0}, check path and permissions" -f $outputfile) return } } else { Write-Warning ("No results found, exiting...") return } } #Output to .xlsx file if ($outputfile.EndsWith('.xlsx')) { if ($results) { try { #Test path and remove empty file afterwards because xlsx is corrupted if not New-Item -Path $outputfile -ItemType File -Force:$true -Confirm:$false -ErrorAction Stop | Out-Null Remove-Item -Path $outputfile -Force:$true -Confirm:$false | Out-Null #Install ImportExcel module if needed if (-not (Get-Module -Name importexcel -ListAvailable)) { Write-Warning ("`nImportExcel PowerShell Module was not found, installing...") Install-Module ImportExcel -Scope CurrentUser -Force:$true Import-Module ImportExcel } Import-Module ImportExcel $results | Sort-Object Name | Export-Excel -AutoSize -BoldTopRow -FreezeTopRow -AutoFilter -Path $outputfile Write-Host ("`nExported results to {0}" -f $outputfile) -ForegroundColor Green } catch { Write-Warning ("`nCould not export results to {0}, check path and permissions" -f $outputfile) return } } else { Write-Warning ("No results found, exiting...") return } } #Output to screen if -Outputfile was not specified if (-not $outputfile) { if ($results) { return $results | Format-Table -AutoSize } else { Write-Warning ("No results found, exiting...") } }}

Download the script(s) from GitHubhere.

Related blog post

PowerShell is fun :)Report from which PowerShell module the cmdlets are from (2024)
Top Articles
Latest Posts
Article information

Author: Carmelo Roob

Last Updated:

Views: 6323

Rating: 4.4 / 5 (45 voted)

Reviews: 84% of readers found this page helpful

Author information

Name: Carmelo Roob

Birthday: 1995-01-09

Address: Apt. 915 481 Sipes Cliff, New Gonzalobury, CO 80176

Phone: +6773780339780

Job: Sales Executive

Hobby: Gaming, Jogging, Rugby, Video gaming, Handball, Ice skating, Web surfing

Introduction: My name is Carmelo Roob, I am a modern, handsome, delightful, comfortable, attractive, vast, good person who loves writing and wants to share my knowledge and understanding with you.