// Visit one the other variations: // - Dotting scripts // - Setting aliases // - Importing modules // - Exporting module members public override AstVisitAction VisitCommand(CommandAst commandAst) { string commandName = commandAst.GetCommandName() ?? GetSafeValueVisitor.GetSafeValue(commandAst.CommandElements[0], null, GetSafeValueVisitor.SafeValueContext.ModuleAnalysis) as string; if (commandName == null) { return(AstVisitAction.SkipChildren); } // They are trying to dot a script if (commandAst.InvocationOperator == TokenKind.Dot) { // . Foo-Bar4.ps1 // . $psScriptRoot\Foo-Bar.ps1 -Bing Baz // . ""$psScriptRoot\Support Files\Foo-Bar2.ps1"" -Bing Baz // . '$psScriptRoot\Support Files\Foo-Bar3.ps1' -Bing Baz DiscoveredModules.Add( new RequiredModuleInfo { Name = commandName, CommandsToPostFilter = new List <string>() }); ModuleIntrinsics.Tracer.WriteLine("Module dots {0}", commandName); } // They are setting an alias. if (string.Equals(commandName, "New-Alias", StringComparison.OrdinalIgnoreCase) || string.Equals(commandName, "Microsoft.PowerShell.Utility\\New-Alias", StringComparison.OrdinalIgnoreCase) || string.Equals(commandName, "Set-Alias", StringComparison.OrdinalIgnoreCase) || string.Equals(commandName, "Microsoft.PowerShell.Utility\\Set-Alias", StringComparison.OrdinalIgnoreCase) || string.Equals(commandName, "nal", StringComparison.OrdinalIgnoreCase) || string.Equals(commandName, "sal", StringComparison.OrdinalIgnoreCase)) { // Set-Alias Foo-Bar5 Foo-Bar // Set-Alias -Name Foo-Bar6 -Value Foo-Bar // sal Foo-Bar7 Foo-Bar // sal -Value Foo-Bar -Name Foo-Bar8 var boundParameters = DoPsuedoParameterBinding(commandAst, commandName); var name = boundParameters["Name"] as string; if (!string.IsNullOrEmpty(name)) { var value = boundParameters["Value"] as string; if (!string.IsNullOrEmpty(value)) { // These aren't stored in DiscoveredExports, as they are only // exported after the user calls Export-ModuleMember. DiscoveredAliases[name] = value; ModuleIntrinsics.Tracer.WriteLine("Module defines alias: {0} = {1}", name, value); } } return(AstVisitAction.SkipChildren); } // They are importing a module if (string.Equals(commandName, "Import-Module", StringComparison.OrdinalIgnoreCase) || string.Equals(commandName, "ipmo", StringComparison.OrdinalIgnoreCase)) { // Import-Module Module1 // Import-Module Module2 -Function Foo-Module2*, Foo-Module2Second* -Cmdlet Foo-Module2Cmdlet,Foo-Module2Cmdlet* // Import-Module Module3 -Function Foo-Module3Command1, Foo-Module3Command2 // Import-Module Module4, // Module5 // Import-Module -Name Module6, // Module7 -Global var boundParameters = DoPsuedoParameterBinding(commandAst, commandName); List <string> commandsToPostFilter = new List <string>(); Action <string> onEachCommand = importedCommandName => { commandsToPostFilter.Add(importedCommandName); }; // Process any exports from the module that we determine from // the -Function, -Cmdlet, or -Alias parameters ProcessCmdletArguments(boundParameters["Function"], onEachCommand); ProcessCmdletArguments(boundParameters["Cmdlet"], onEachCommand); ProcessCmdletArguments(boundParameters["Alias"], onEachCommand); // Now, go through all of the discovered modules on Import-Module // and register them for deeper investigation. Action <string> onEachModule = moduleName => { ModuleIntrinsics.Tracer.WriteLine("Discovered module import: {0}", moduleName); DiscoveredModules.Add( new RequiredModuleInfo { Name = moduleName, CommandsToPostFilter = commandsToPostFilter }); }; ProcessCmdletArguments(boundParameters["Name"], onEachModule); return(AstVisitAction.SkipChildren); } // They are exporting a module member if (string.Equals(commandName, "Export-ModuleMember", StringComparison.OrdinalIgnoreCase) || string.Equals(commandName, "Microsoft.PowerShell.Core\\Export-ModuleMember", StringComparison.OrdinalIgnoreCase) || string.Equals(commandName, "$script:ExportModuleMember", StringComparison.OrdinalIgnoreCase)) { // Export-ModuleMember * // Export-ModuleMember Exported-UnNamedModuleMember // Export-ModuleMember -Function Exported-FunctionModuleMember1, Exported-FunctionModuleMember2 -Cmdlet Exported-CmdletModuleMember ` // -Alias Exported-AliasModuleMember // & $script:ExportModuleMember -Function (...) var boundParameters = DoPsuedoParameterBinding(commandAst, commandName); Action <string> onEachFunction = exportedCommandName => { DiscoveredCommandFilters.Add(exportedCommandName); ModuleIntrinsics.Tracer.WriteLine("Discovered explicit export: {0}", exportedCommandName); // If the export doesn't contain wildcards, then add it to the // discovered commands as well. It is likely that they created // the command dynamically if ((!WildcardPattern.ContainsWildcardCharacters(exportedCommandName)) && (!DiscoveredExports.Contains(exportedCommandName))) { DiscoveredExports.Add(exportedCommandName); } }; ProcessCmdletArguments(boundParameters["Function"], onEachFunction); ProcessCmdletArguments(boundParameters["Cmdlet"], onEachFunction); Action <string> onEachAlias = exportedAlias => { DiscoveredCommandFilters.Add(exportedAlias); // If the export doesn't contain wildcards, then add it to the // discovered commands as well. It is likely that they created // the command dynamically if (!WildcardPattern.ContainsWildcardCharacters(exportedAlias)) { DiscoveredAliases[exportedAlias] = null; } }; ProcessCmdletArguments(boundParameters["Alias"], onEachAlias); return(AstVisitAction.SkipChildren); } // They are exporting a module member using our advanced 'public' function // that we've presented in many demos if ((string.Equals(commandName, "public", StringComparison.OrdinalIgnoreCase)) && (commandAst.CommandElements.Count > 2)) { // public function Publicly-ExportedFunction // public alias Publicly-ExportedAlias string publicCommandName = commandAst.CommandElements[2].ToString().Trim(); DiscoveredExports.Add(publicCommandName); DiscoveredCommandFilters.Add(publicCommandName); } return(AstVisitAction.SkipChildren); }