Building on @Daniel's approach.... a helper function like this:
function Get-ModuleInventory {
param (
[Parameter(Mandatory = $true)] [scriptblock] $ScriptBlock
)
# Find all commands in this script
$cmdlets = $ScriptBlock.Ast.FindAll( { $args[0] -is [System.Management.Automation.Language.CommandAst] }, $true) | ForEach-Object{
Write-Output $_.CommandElements[0].Value
}
$cmdlets | Select-Object -Unique | Get-Command | Where-Object {$_.Source} | Sort-Object -Property Source | Group-Object -Property Source | ForEach-Object {
if($module = Get-Module $_.Name) {
[PSCustomObject]@{
ModuleName = $module.Name
ModuleVersion = $module.Version.ToString()
ModulePath = $module.Path
ModuleCommandsUsed = $_.Group.Name
} | Write-Output
}
}
}
can be called from a script like this:
$modulesUsed = Get-ModuleInventory -ScriptBlock $MyInvocation.MyCommand.ScriptBlock
Write-Host "### BEGIN MODULE MANIFEST"
$modulesUsed | ConvertTo-Json | Write-Host
Write-Host "### END MODULE MANIFEST`r`n"
which will produce a handy list of the modules used (including version and whether the module was installed for all users or just the current user. This is handy if you're trying to understand, for example, why a script runs from a dev workstation but not as a scheduled task on a job server.
{
"ModuleName": "Az.Resources",
"ModuleVersion": "8.0.1",
"ModulePath": "C:\\Users\\xxx\\Documents\\PowerShell\\Modules\\Az.Resources\\8.0.1\\Az.Resources.psm1",
"ModuleCommandsUsed": [
"Get-AzResourceProvider",
"Get-AzResourceGroup",
"Get-AzResource"
]
},
{
"ModuleName": "Microsoft.PowerShell.Management",
"ModuleVersion": "7.0.0.0",
"ModulePath": "C:\\program files\\powershell\\7\\Modules\\Microsoft.PowerShell.Management\\Microsoft.PowerShell.Management.psd1",
"ModuleCommandsUsed": "Split-Path"
},