Power shell — это веселье

I’m trying to apply the changes required to meet the CIS Benchmark “4.6 Ensure ‘HTTP Trace Method’ is disabled”. I can get the verbs, I have so far been unabled to Add verbs to the ‘requestFiltering’.

I can get the verbs..

$requestConfigSection = Get-IISConfigSection -SectionPath 'system.webServer/security/requestFiltering'
$verbsElements = Get-IISConfigElement -ConfigElement $requestConfigSection -ChildElementName 'verbs'

If trace was already present, I could get it like so.

$traceVerb = Get-IISConfigAttributeValue -ConfigElement $verbsElements -AttributeName 'trace'

And set it like this.

Set-IISConfigAttributeValue -ConfigElement $verbsElements -AttributeName 'trace' -AttributeValue $false
Add-WebConfigurationProperty -pspath 'MACHINE/WEBROOT/APPHOST' -filter "system.webServer/security/requestFiltering/verbs" -name "." -value @{verb='TRACE';allowed='False'}
(Get-iisserverManager).GetApplicationHostConfiguration().GetSection("system.webServer/security/requestFiltering").GetChildElement('verbs')

I do get a result with with GetCollection(), but not what I would expect.

$requestSection = (Get-iisserverManager).GetApplicationHostConfiguration().GetSection("system.webServer/security/requestFiltering")
$requestSection.GetCollection('verbs')   #empty ConfigurationElement result
$requestSection.GetChildElement('verbs')   #produces the following

Attributes      : {allowUnlisted, applyToWebDAV}
ChildElements   : {}
ElementTagName  : verbs
IsLocallyStored : True
Methods         :
RawAttributes   : {[allowUnlisted, True], [applyToWebDAV, True]}
Schema          : Microsoft.Web.Administration.ConfigurationElementSchema

To those preferring a full PowerShell result, I am getting the same result using.

$verbsCollection = Get-IISConfigCollection -ConfigElement $requestConfigSection -CollectionName 'verbs'
$verbsCollection.GetType()  # confirms empty colleciton of type ConfigurationElementCollection

I will discuss everything about the PowerShell naming conventions in this PowerShell tutorial.

When you work with PowerShell, adhering to established naming conventions improves the readability and maintainability of your scripts and modules.

Scripts and Modules: When naming scripts and modules, choose names that succinctly describe their functionality. Avoid abbreviations and instead, opt for full words to eliminate ambiguity.

EntityConvention Example
CmdletGet-Item
FunctionConvertTo-Json
Variable$totalCount
ScriptBackup-Server.ps1
ModuleUserManagement.psm1

Remember, consistency across your cmdlets, variables, scripts, and modules benefits you and others who may use or maintain your code in the future. By sticking to these foundational conventions, you’ll enhance the clarity and professionalism of your PowerShell scripts.

PowerShell Cmdlet Naming

In PowerShell, cmdlet naming is a systematic way of providing clear, self-descriptive commands. This convention ensures consistency across the PowerShell ecosystem, making it easier for you to recognize and utilize cmdlets effectively.

Verb-Noun Pair Usage

Standard Verb Definitions and Usage

PowerShell defines a set of approved verbs to ensure uniformity in the actions that cmdlets perform. Using Get-Verb can provide you with the list of these verbs. For common actions like creating, you should use New, for reading, opt for Get, and for updates, apply Set. Here’s a brief list of some standard verbs with their intended actions:

  • Get: Retrieve data
  • Set: Modify existing data
  • Add: Append data
  • Remove: Delete data
  • New: Create new instances
  • Make certain to use these approved verbs to make your cmdlets intuitive and aligned with the cmdlets created by others.

Noun Naming Best Practices

When naming the noun part of a cmdlet, you should be specific and avoid ambiguity. The noun should reflect the entity that the cmdlet is acting upon and should not contain a verb. Avoid using plural nouns to keep in line with PowerShell’s naming convention. Here are examples of good noun usage:

  • For a cmdlet that lists processes: Get-Process (not Get-Processes)
  • To copy a file: Copy-Item (not Copy-Items or Copy-File)

PowerShell Script and Function Structure

In PowerShell, the structure of your scripts and functions greatly contributes to their clarity and ease of use. Correct naming and design ensure that your code is accessible and maintainable.

Script Module Design

Your script module acts as a container for a group of functions. It is essential to:

  • Use a descriptive name in PascalCase, such as UserManagement or NetworkDiagnostics.
  • Include a .psm1 file that contains your functions, and a .psd1 manifest file which describes the module and its dependencies.

PowerShell Function Definition Conventions

  • Names follow the <Verb>-<Noun> format, with PascalCase for the noun, e.g., Get-Process.
  • The verb should be from the approved list, retrievable by executing Get-Verb.
  • For advanced functions, use the CmdletBinding attribute to enable cmdlet-like features.

Parameter Naming Best Practices

Parameters are crucial for script flexibility. Ensure your parameter names are:

  • Clear and descriptive: e.g., -FilePath instead of -Path.
  • PascalCase with no underscores or hyphens, e.g., -UserName.

For parameters accepting specific values:

  • Use the ValidateSet attribute to restrict inputs, which improves usability and reduces errors.
  • To accept input from the pipeline, use the ValueFromPipeline attribute, allowing users to pipe values directly to the parameter.

PowerShell Variables and Arrays Naming Conventions

In PowerShell, successful scripting hinges on your ability to handle variables and arrays effectively. Proper naming and usage of these entities increase readability and maintainability.

Variable Naming Guidelines

When you name variables:

  • Avoid Reserved Words: Do not use keywords reserved by PowerShell, such as $true, $false, $null, or loop and conditional keywords like $for and $while.
  • Be Descriptive: Your variable names should clearly indicate their purpose or content, promoting code readability. For example, use $userName instead of $un.
  • Consider Scope Prefixes: Incorporate scope prefixes to clarify variable reach. Use $local:VarName for local scope, $script:VarName for script scope, and consider $global:VarName for global variables when necessary.

Array Usage and Naming Conventions

Arrays are fundamental for handling collections of items.

  • Declare with Intent: Define an array with a specific purpose, ensuring the name reflects the content, such as $processList for an array of processes.
  • Initialization Syntax: You can declare an array with $myArray = @() and populate it with elements, $myArray = 'element1', 'element2'.
  • Accepting Arrays as Parameters: When writing cmdlets or functions, allow an array parameter to enable bulk operations, like in Get-Process -Name $processNames.

PowerShell arrays and variables named and used judiciously empower your scripts with efficiency and fluidity.

PowerShell Best Practices for Error Handling and Debugging

Effective error handling and debugging are vital for creating robust scripts in PowerShell. You’ll need to manage script errors strategically and have the skills to debug scripts when issues arise.

Using ErrorAction Parameter

The -ErrorAction parameter is crucial for controlling how PowerShell responds to non-terminating errors. You can specify behaviors like Stop, Continue, SilentlyContinue, or Inquire. Here’s a brief rundown:

  • Stop: Halts the execution of the script when an error is encountered.
  • Continue: Default behavior that prints the error message and continues execution.
  • SilentlyContinue: Suppresses the error message and continues execution.
  • Inquire: Prompts you for action when an error occurs.

Remember to use -ErrorAction with cmdlets to define error handling behavior inline.

Get-Item "Path\To\Nonexistent\File" -ErrorAction Stop

Debugging PowerShell Scripts

When debugging, leverage PowerShell’s built-in debugger. Use breakpoints to pause script execution and analyze the current state. There are several types of breakpoints:

  • Line Breakpoints: Pause execution at a specific line.
  • Variable Breakpoints: Trigger when a variable is accessed or modified.
  • Command Breakpoints: Halt when a specific command is about to run.

Setting a Line Breakpoint:

Set-PSBreakpoint -Script "script.ps1" -Line 15

Additionally, use the Debug parameter with cmdlets to trigger the debugger when an error occurs in the cmdlet.

Invoke-Command -ScriptBlock { param($path) Get-Content $path } -ArgumentList "Path\To\File" -Debug

Understanding and using these tools will significantly enhance your PowerShell scripting experience by allowing you to handle errors and debug more efficiently.

PowerShell Naming Conventions

Best Practices for PowerShell Code Readability

When writing PowerShell scripts, adhering to clear naming conventions greatly enhances your code’s readability. You should name your cmdlets, functions, and variables with precision to reflect their purpose and functionality.

Cmdlet Naming: Always use Pascal case for cmdlets names (e.g., Get-Item). It’s an adopted standard in PowerShell that aligns with .NET framework conventions, making your cmdlets easily recognizable.

Function Names: Similar to cmdlets, use Pascal case and specific nouns for function names (e.g., ConvertTo-Json). This not only aids in discoverability but also in understanding the action the function performs.

Braces: Place the opening brace at the end of the function, if, or loop statement, not on a new line. This is a common practice that keeps your code tidy and structured.

  • Examples: function Get-LogContent { Param([string] $Path) # Your code here } if ($errorCondition) { Write-Host "An error occurred." }

Maintaining these best practices in your PowerShell scripts will ensure they are not only readable but maintainable for both you and others who may use or modify your code in the future.

PowerShell Security and Execution Policies

When working with PowerShell, your security is paramount. PowerShell includes an execution policy feature, which is a crucial aspect of your scripting environment’s security. Execution policies determine the conditions under which PowerShell loads configuration files and runs scripts, helping to prevent the execution of unauthorized or malicious scripts.

Here’s how you can manage execution policies:

  • View Current Policy: Use Get-ExecutionPolicy to check the current execution policy setting.
  • Set Policy: Change the policy using Set-ExecutionPolicy, with available policies ranging from Restricted (no scripts run) to Unrestricted (all scripts run).

PowerShell’s engine does not enforce the execution policy, but rather serves as a guideline to prevent inadvertent script execution. Keep in mind that execution policies are not defenses against malicious actors, but they do offer a layer of protection for your system.

:/>  Меню админ-ресторана

Execution Policy Scopes:

  • MachinePolicy: Affects all users on the computer.
  • UserPolicy: Applies to the current user profile.
  • Process: Influences only the current PowerShell session.
  • CurrentUser: Targets only the current user.
  • LocalMachine: Applies to all users on the computer.

Remember to always operate within the principles of least privilege, setting execution policies that are as restrictive as necessary for your task but allow your scripts to run efficiently. Use the -Scope parameter to specify which scope you wish to alter when using Set-ExecutionPolicy. If working on Windows, be aware that Group Policy might override your execution policy settings.

# Check the current execution policy
Get-ExecutionPolicy

# Set an execution policy for the current user
Set-ExecutionPolicy -ExecutionPolicy RemoteSigned -Scope CurrentUser

By remaining vigilant and understanding PowerShell’s execution policies, you can ensure an additional layer of security for your scripts and configuration files.

PowerShell Naming Convention Function

Use PascalCase: Capitalize the first letter of each word in the function name, ensuring there are no spaces between words. For example: Get-Process.

Approved Verbs: Select a verb from the list of PowerShell-approved verbs. Retrieve this list by executing Get-Verb.

Singular Nouns: Always use singular nouns to avoid confusion. If your function deals with multiple items, the name should still use the singular form to remain consistent with PowerShell cmdlets.

Prefixes: Consider prefixing nouns to prevent name clashes and provide additional context about the function.

Function NameVerbNounDescription
Convert-ToCsvConvertToCsvConverts objects to a comma-separated value
Get-InventoryItemGetInventoryItemRetrieves information on an inventory item
Set-UserPreferenceSetUserPreferenceModifies a user’s preferences

PowerShell Naming Convention Variables

In PowerShell, adhering to a naming convention for variables enhances script readability and maintainability. Your variable names should clearly indicate their purpose and scope.

PowerShell Local Variable Naming Convention

Local variables in PowerShell are typically named using camelCase. This means you start with a lowercase letter and capitalize the first letter of each subsequent concatenated word. For example:

$localAccountDetails = "Details of a local account"
$invoiceNumber = 12345

Remember, variable names should be descriptive enough to provide clarity on their usage within your code.

PowerShell Constant Variable Naming Convention

When you declare constant variables — values that do not change — use PascalCase. This convention starts with an uppercase letter and capitalizes the first letter of each new word. It is good practice to also include a prefix that indicates the variable is a constant. Here’s an example:

$ConstantTaxRate = 0.05
$MaxAllowedConnections = 100

Using clear and consistent naming conventions for your variables makes your PowerShell scripts more accessible and easier for you and others to understand.

PowerShell Module Naming Convention

  • Verb: Use an approved PowerShell verb that describes the action your module performs.
  • Noun: Choose a noun that clearly identifies the entity or concept acted upon.

Best Practices for Naming Your Module:

  • Ensure the name is concise and descriptive.
  • Avoid using abbreviations that might be unclear to others.
  • Stick with singular nouns, as recommended by PowerShell guidelines.

Example: For a module that manages system backups, a suitable name could be Save-SystemBackup.

Directory and File Naming:

  • Save the PowerShell script with a .psm1 extension and use the same name for the script and the directory where the script is saved. This consistency prevents confusion when importing the module using commands such as Import-Module.

PowerShell Constant Naming Convention

When you define constants in PowerShell, it’s crucial to adopt a clear and consistent naming convention. This aids in making your code more readable and maintainable.

The recommended approach for naming constants is to use a descriptive name that clearly indicates what the constant represents. Typically, constants are written in PascalCase (also known as UpperCamelCase), where the first letter of each word is capitalized, and there are no underscores between words.

Example:

If you’re setting a constant for a maximum size value, you could name it like this:

Set-Variable MaxSize -Option Constant -Value 1024

Best Practices:

  • Descriptive Names: Choose names that reflect the constant’s purpose, as in MaxSize for representing a size limit.
  • PascalCase: Write the constant names using PascalCase for better visibility.
  • Avoid Abbreviations: Use full words rather than abbreviations to make the meaning clear.

When implementing constants in your scripts, remember that a constant cannot be changed once it is set. Attempting to modify a constant will result in an error. PowerShell offers the Set-Variable cmdlet to define a constant, which you should use along with the -Option Constant flag.

Remember, PowerShell constants are immutable. If you need a variable that can be modified but not removed, consider using the -Option ReadOnly.

Here’s a table summarizing the key points:

PropertyRecommendationExample
CasePascalCaseMaxSize
DescriptivenessClear and specific namesDefaultFilePath
ImmutabilitySet with -Option Constant flagSet-Variable usage

By adhering to these conventions, you ensure that your PowerShell script remains structured and comprehensible.

PowerShell Cmdlet Naming Convention

When crafting cmdlets in PowerShell, you must adhere to a specific naming convention that utilizes a verb-noun pair. This ensures that your cmdlets are easily identifiable and the actions they perform are understood at a glance.

Verb Usage: Choose a verb from the approved list by PowerShell, as these verbs convey standardized actions within the naming convention.

  • Get: Retrieve data without changing the system state.
  • Set: Modify data or system state.
  • Start: Initiate a process or task.
  • Get-Process
  • Set-Date
  • Start-Service
  • Consistency: Stick with the established patterns to ensure reliability across different scripts and modules.
  • Clarity: Use clear and descriptive nouns that accurately reflect the entities your cmdlet operates on.

Frequently Asked Questions

What are the best practices for naming functions in PowerShell?

When naming functions, use a Verb-Noun format with each word capitalized, such as Get-Process. Choose verbs from the standard PowerShell verb list to maintain consistency.

How should I structure the naming of modules in PowerShell?

What should I consider when using verbs in PowerShell command names?

Use approved verbs from the PowerShell verb list for your command names. For instance, use Get for retrieval operations and Set for modifying operations. Stick to these standardized verbs to ensure compatibility and predictability.

How does camelCase notation fit within PowerShell scripting standards?

Can you explain the significance of the PS1 file naming convention in PowerShell?

.ps1 is the file extension for PowerShell scripts. When naming these files, use descriptive phrases that summarize their function, separated by dashes, like backup-database.ps1. This naming aids in quickly identifying the script’s purpose.

What guidelines exist for naming parameters in PowerShell scripts?

Conclusion

I have explained everything about the PowerShell naming conventions and best practices in this PowerShell tutorial. We covered:

  • PowerShell Naming Conventions for Functions
  • PowerShell Naming Convention for Variables
  • PowerShell Module Naming Conventions
  • PowerShell Constant Naming Conventions
  • PowerShell Cmdlet Naming Conventions

You may also like:

When it comes to PowerShell scripting, consistent naming conventions make the task of building robust solutions much easier. The good news is that there are PowerShell approved verbs you can use when writing scripts and commands.

In this tutorial, you will learn which approved verbs to use in PowerShell through a series of examples.

Jump right in and level up your PowerShell scripting!

Retrieving a List of PowerShell Approved Verbs

In PowerShell, cmdlets are small, single-function commands that perform specific actions in the PowerShell environment.

  • The verb part of the name describes the action that the cmdlet performs. Some common verbs used in PowerShell are as follows:
VerbFunction
GetRetrieves information.
SetChanges or updates settings.
NewCreates something new.
RemoveDeletes or removes something.
  • The noun part of the name identifies the entity or object on which the action is performed, the target to take action upon. The noun typically describes the category or type of object the cmdlet interacts with, such as command, process, service, or file.

To see all approved verbs you can use for your script:

The output below shows just a few verbs you can use for your script.

powershell approved verbs - Retrieving a complete list of approved verbs
Retrieving a complete list of approved verbs

Now, run the same command as below, but this time, you will list all approved verbs that start with re via a wildcard search. Doing so narrows down the list of verbs to those associated with reset, resize, redo, and so on.

As shown below, narrowing down the list of verbs can be helpful when you have a specific action in mind and wish to find a verb that closely matches that action.

:/>  Как зайти в MSConfig в Windows 10
Narrowing down the list of approved verbs
Narrowing down the list of approved verbs

Creating New Resources via the New Verb

New-LocalUser -Name "John Smith" -AccountNeverExpires -Password (ConvertTo-SecureString -AsPlainText "Password123" -Force
Creating a new resource (user account) via the New verb
Creating a new resource (user account) via the New verb

Retrieving Resource Information via the Get Verb

Besides creating new resources, PowerShell also has a verb that lets you retrieve information about any of your existing resources. In PowerShell, the Get verb is commonly used to retrieve or fetch information about a particular resource, such as the OS, services, files, and other objects.

To retrieve resource information via the Get verb:

Get-LocalUser -Name "John Smith"
Retrieving resource information via the Get verb
Retrieving resource information via the Get verb

Modifying Existing Resources via the Set Verb

Imagine you noticed something was off after seeing one of your resource’s information. How can you modify an existing resource? Worry not! A PowerShell-approved verb, the Set verb, allows you to make changes to existing resources.

Instead of recreating resources, the Set verb lets you adjust by modifying their properties or configurations.

To modify existing resources via the Set verb:

# Define a variable resource
$myVariable = "Hello"

# Modify the value of an existing variable resource
Set-Variable -Name myVariable -Value "Hello, World!"

Now, run the Get-Variable command below to retrieve information about your resource ($myVariable).

Get-Variable -Name myVariable

As shown below, the output shows the variable’s name and value.

Retrieving information about a resource
Retrieving information about a resource

Triggering Actions or Invoking Commands via the Invoke Verb

Instead of manually running commands, as you did in the previous examples, why not automate them in a PowerShell script? How? The Invoke verb allows you to initiate actions or invoke commands programmatically.

With a PowerShell script and the Invoke verb, you can run multiple PowerShell commands at once without typing them all in the console.

To see how triggering actions work via the Invoke verb:

Invoke-Expression -Command "Get-Date"

The output below shows a successful execution of the Get-Date command via the Invoke verb.

Triggering a command via the Invoke verb
Triggering a command via the Invoke verb

This code displays (Write-Host) a welcome message and invokes the Get-Service cmdlet to list all services in your system.

# Display a warm welcome message
Write-Host "Welcome to the Invoke Example!"

# Invoke the Get-Service cmdlet
Invoke-Command -ScriptBlock { Get-Service }
$scriptPath = "C:\PowerShellScripts\InvokeVerbDemo.ps1"
Invoke-Expression -Command $scriptPath

The output below shows a welcome message and a list of all services in your system, which confirms a successful execution of your script.

Invoking a script via the Invoke verb
Invoking a script via the Invoke verb

4. Instead of just commands, write a reusable function (i.e., Invoke-MyTask) that you can call at any time, as shown below. Essentially, functions enhance the maintainability and reusability of your PowerShell scripts.

  • Displays (Write-Host) the string Executing MyTask... on the console.
  • Retrieves the list of all processes (Get-Process) and selects only (Select-Object) the Name and CPU properties for each process.
# Define a custom function using the Invoke verb
function Invoke-MyTask {
    # Your custom task goes here
    Write-Host "Executing MyTask..."
    Get-Process | Select-Object Name, CPU
}
Defining a PowerShell function
Defining a PowerShell function

5. Lastly, execute the below command to invoke your function (Invoke-MyTask).

Invoke-Expression -Command Invoke-MyTask

You will see a list of all processes running on your system with their names and CPU usage, as shown below.

Invoking a function
Invoking a function

Validating Resources via the Test Verb

Ensuring the accuracy of input values and conditions is paramount when crafting robust and error-resistant PowerShell scripts. One powerful tool at your disposal for this purpose is the Test verb.

By employing the Test verb, you can quickly verify whether a given condition holds a true or false value, enabling you to execute different actions based on the outcome. In this example, you will validate if a file exists via the Test verb.

Execute the code below to test (Test-Path) whether a file exists (C:\MyFolder\example.txt) at the specified $filePath, and print a message depending on the result.

# Define a file path.
$filePath = "C:\MyFolder\example.txt"

# Test if the file exists, and print a message depending on the result
if (Test-Path $filePath) {
    Write-Host "The file exists at $filePath."
}
else {
    Write-Host "The file does not exist at $filePath."
}
Validating a resource via the Test verb
Validating a resource via the Test verb

Conclusion

You now have a basic understanding of PowerShell-approved verbs and how to use them effectively in your scripts and commands. By leveraging these verbs, you can now create robust, efficient, and consistent PowerShell solutions for various tasks and scenarios.

PowerShell is a great tool for programmers and nonprogrammers alike. The ability to automate both simple and complex scripts is invaluable to businesses. One of the more difficult aspects of automation is writing loops for your scripts. Loops are essential to automating time-consuming, mundane tasks. 

In this PowerShell tutorial, we’ll show you how to use the For loop, ForEach-Object loop, and the While, Do-While and Do-Until loops.

What is PowerShell?

PowerShell is an open-source scripting language that’s used to design efficient scripts and tools to assist people in their daily work tasks. PowerShell was originally designed with the intention of being easy to understand, so it’s great for people who may not be familiar with software programming. 

PowerShell has two primary functions: a command-line shell that is similar to the Windows command prompt (known as “cmd.exe”) and a robust scripting language that can be molded to automate practically anything you might need.

In 2002, Jeffrey Snover, who worked for Microsoft at the time, knew that the command-line interface for Windows was not as capable as Linux, Microsoft’s competitor. To solve this problem, he created a document outlining his plans for a program that could improve upon the old command lines. Thus, PowerShell was born. 

Since 2016, PowerShell has been available on macOS, Linux and other *nix operating systems.

If you need to know which verbs are accepted, try using Get-Verb.

Programming with loops

PowerShell loops, at their most basic, simply repeat a set of commands a certain number of times. Ideal for performing consistent actions for a set period of time or a certain number of records, loops can simplify scripts and build interactive menus. In particular, PowerShell features cmdlets — notably, those that begin with the verb Get — that return objects containing large numbers of similar data.

There are several loop types available in PowerShell, and in many cases, more than one loop technique can be used effectively. At times, you must determine the most efficient loop type, from either a performance or code readability perspective.

ForEach-Object loop

PowerShell screenshot

$myDocuments = Get-ChildItem 

Because loops perform consistent acts on a given set of data, you can use PowerShell to sync files and folders using a ForEach loop.

PowerShell For loop

PowerShell screenshot

While, Do-While and Do-Until loops

PowerShell screenshot

The third type of loop that PowerShell supports involves setting a condition that allows the loop to process either as long as the condition is true or until it is met. Both While and Do-While loops are used to perform an action while the condition evaluates to $true, and they differ only in their syntax. Do-Until loops have a similar syntax as Do-While loops, but they stop processing once the condition statement is met.

While ($i -le 10)

$i++
}
Until ($i -gt 10)

Any of these three loop types — Do-While, Do-Until and While — can also be used to loop indefinitely: While and Do-While loops with the condition set to $true and Do-Until loops with the condition set to $false.

Make sure you understand which loop type is necessary for your script building: For, While, Do-While or Do-Until.

In some situations, you may need to exit a loop early based on something other than the loop’s condition. In this case, the Break keyword can be invoked to exit the loop. This final example shows the same functionality, but it uses an infinite loop and the Break keyword to exit at the appropriate time:

By wrapping your loops and other code within functions, you can create and use modules in PowerShell to make your scripts more organized and easier to maintain.

Why businesses should use PowerShell and loops

One of the benefits of customer relationship management (CRM) systems and the best electronic medical record (EMR) platforms is their ability to automate repetitive tasks and workflows. One drawback is that when customizing your system, you must stay within the set parameters.

PowerShell loops — such as For, ForEach-Object, While, Do-While and Do-Until — give you much greater freedom and control. They allow you to automate data entry, process large data sets on a scheduled basis, and integrate various systems exactly the way you want.

The less time you and your staff spend on repetitive, mundane tasks, the more time you have to think and act strategically to grow the business.

Mark Fairlie and Sean Peek contributed to this article.

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.

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.) You can add your custom verbs to $customverbs in the script, and added a “powershellisfun” custom verb there as a start value 😉

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

Resolve-CmdletsToModules -clipboard
Power shell — это веселье

You can copy small or significant 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

I used the -Cmdlets parameter in the example below 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
Power shell — это веселье

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
Power shell — это веселье

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
Power shell — это веселье

The Excel file looks like this:

Power shell — это веселье

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

- 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 / Get-Verb
    #Add your own if needed to $customverbs
    $verbs = (Get-Verb).Verb
    $customverbs = @(
        "powershellisfun"
    )
    $verbs += $customverbs

    #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 GitHub here.

Оставьте комментарий