Displays information about the success of a powershell command. How to create commands and functions in Powershell, call them and pass parameters


PowerShell is an object-oriented software engine and scripting language with a command line interface that provides IT professionals with greater opportunities for configuring operating systems of the MS Windows family. Simply put, it is a kind of universal administration tool. This article will discuss basic techniques for writing scripts in PowerShell, which allow you to automate the management of your Windows environment in a simple way.

PowerShell offers both a pure console interface and a full development environment PowerShell ISE(Integrated Scripting Environment, built-in scripting environment) for scripts. To launch the command line interface, type powershell in the Run menu (WinKey + R). PowerShell ISE is launched using the "PowerShell ISE" command in the same menu.

ISE is more preferable as it provides more opportunities to the developer thanks to syntax highlighting, code auto-completion and other features inherent in many “big” IDEs.

Writing and running scripts

Scripts are saved as files with the extension .ps1. Even though PowerShell has long been a native part of the Windows OS, you can't run its scripts with a simple double-click. To do this, right-click on the script and select “Run in PowerShell”.

There are also system policies that restrict script execution. You can check your current policy settings by running the Get-ExecutionPolicy command. The result will be one of the following values:

  • Restricted- execution of scripts is prohibited. Standard configuration;
  • AllSigned- you can run scripts signed by a trusted developer; Before running the script, PowerShell will ask you for confirmation;
  • RemoteSigned- you can run your own scripts or those signed by a trusted developer;
  • Unrestricted- you can run any scripts.

To get started, you need to change the startup policy setting to RemoteSigned using the Set-ExecutionPolicy command:

Cmdlets

Cmdlets are commands with a predefined function, similar to conditional statements in programming languages. They have several key features:

  • There are system, user and optional cmdlets;
  • the result of executing the cmdlet will be an object or an array of objects;
  • Cmdlets can process data and pass it to other cmdlets using pipelines;
  • cmdlets are case insensitive, so there is no difference between Get-ADUser , get-aduser , and gEt-AdUsEr ;
  • a symbol is used as a separator; .

Each cmdlet contains a verb and a noun separated by a hyphen. For example:

  • Get-Process- display current processes running on the computer;
  • Get-Service- display a list of services and their status;
  • Get-Content- display the contents of the specified file, for example Get-Content C:\Windows\System32\drivers\etc\hosts .

If necessary, you can list all available cmdlets using Get-Help-Category:

You can also create your own cmdlets.

Options

Each cmdlet has several parameters that determine how it works. PowerShell ISE automatically suggests all available parameters and displays their type. For example, Get-Service-NameW* returns a list of services whose name begins with W . If you forget what parameters the cmdlet you entered has, use Get-Member . For example, Get-Process | Get-Member:

If you don't find what you need, or aren't sure how to set the parameters correctly, you can even request examples using the -Examples parameter:

Some cmdlets can also be called using aliases, for example, instead of Get-Help you can simply write Help .

When writing large scripts or team development, you can use comments. Each comment begins with a # character, and the comment block is limited to combinations of characters<# и #>at the beginning and at the end respectively.

Conveyor

PowerShell Allows you to exchange data between cmdlets using a pipeline. For example:

  • GetService | SortObject -property Status - sorting running services by status;
  • “Hello World!” | Out-File C:\ps\test.txt - writing text to a file.

Multiple conveyors can be used. For example, the following script lists the names of all services except stopped ones:

Get-Service | WHERE ($_.status -eq “Running”) | SELECT displayname

Conclusion

So, thanks to this tutorial, newbies have an idea of ​​what PowerShell is all about. We also looked at options for changing the script execution policy, what a cmdlet is, how they exchange data using a pipeline, and how to get the properties of the desired object. Remember that if you have any problems, you can use the Get-Help cmdlet.

This article is a text version of a lesson from our free PowerShell and Active Directory Basics video course (use the secret word "blog" for full access).

This video course has proven to be extremely popular around the world and will take you through all the steps to create a complete set of tools for managing the Active Directory directory service, starting from the very basics.

Coding with PowerShell

At first, it may seem like a daunting task to get started with PowerShell, especially if over the years you have become accustomed to working with the cmd.exe command line and the so-called “batniks” (files with the .bat and .cmd extensions). In this article, written based on materials from lesson 2 of our video course, we will tell you how and why you should update your PowerShell skills, and also look at the basics of launching the PowerShell editor, master command auto-completion, and how to get up-to-date information in any difficult situation. help and examples.

Executing Commands

The PowerShell console is an interactive environment that allows you to run various commands in real time. Here you do not need to first edit the script in Notepad and only then run it on the command line, which will also significantly save your time.

If you currently work in any organization that exists for more than one day, then you probably already have several small scripts for every day that you run from the cmd.exe command line. And this is great news! This means you can just as easily do all this from PowerShell. This was truly a smart design decision on Microsoft's part, as they made the transition to the new solution easier for administrators.

In appearance, the PowerShell editor looks and functions exactly the same as the cmd.exe command line environment. The techniques and skills you already know will work unchanged in PowerShell. And if you're also looking to upskill yourself and are working to move away from one-off tasks to more automated administration, getting into the habit of running PowerShell rather than the Command Prompt is a great way to start.

All your frequently used utilities such as ping, ipconfig, nslookup, etc. will work exactly as you expect.

How to find PowerShell commands

People love PowerShell because it's so, well, powerful! But that power comes from the absolutely insane amount of built-in capabilities. It's simply not possible, and probably not practical, for someone to remember all the different commands, cmdlets, flags, filters and other ways to tell PowerShell what to do and how to do it.

Luckily, there are several tools built right into the editor to help you deal with this.

Auto-completion of commands by pressing Tab

There is no need to remember different commands or the exact spelling of a command. Dial

Get-c
Now, by pressing the Tab key, you can go through all the available commands starting with the characters that you have already entered. Moreover, this works in any part of the command body that you are trying to reference: in command names and flags, and even when autocompleting full paths on the file system.

Get-Command

Even though Tab completion works great, what happens if you don't know the correct name of the command you need? In this case, you can use the command to find other available commands: Get-Command.

When looking for a command name, it is important to keep in mind that there is a syntax for them: Verb-Noun. Typically, Verbs such as – Get, Set, Add, Clear, Read and Write and Nouns – files, servers or other entities on your network and applications .

Get-Command is a tool for searching and exploring the commands available on your computer.

Command Syntax in PowerShell

Someone once described the Perl scripting language as “executable line noise”—an incredibly useful tool, with a wildly opaque syntax and a correspondingly high barrier to entry for learning it.

Although if you look at it, the traditional command line in Windows is not so far from this. Consider the general problem of finding all files in a directory whose names begin with 'foo'.

CMD: FOR /D /R %G IN (“Foo*”) DO @ECHO %G
FOR and DO indicate that this is a loop.
The /D flag indicates that this is a loop through all folders
The /R flag specifies to include all files and folders, including subdirectories
The search pattern that defines the set of files we are interested in is indicated by “IN”
ECHO indicates that the script should print the result of each loop and finally
%G is a “forced parameter” and was chosen because Microsoft programmers had previously used the letters A, D, F, N, P, S, T, and X during development. Therefore, starting with G is good form, i.e. To. this gives you the largest set of unused letters for the returned variable path formats (G, H, I, J, K, L, M) - in other words, it's a life hack.

Now compare the PowerShell equivalent:

PowerShell: Get-ChildItem -Path C:\ -Filter ‘Foo*’
The result is the same, but even with such a fairly trivial example, it will be much easier to understand what is happening. It's immediately obvious what each element in the command does and how you can change them. Well, maybe the wildcard '*' is used in both examples, but I think you already know very well what it means - that all elements should start with 'Foo' and something else at the end.

Do you feel your mood gradually improving? Now, what if you want to know how to select only files (not folders) in a path? Can you dig into the manuals, or can your best friend Google help you, or can you try to figure it out from the command line? Quick tip: if you're in PowerShell, type “-” and press Tab, go through the flags until the obvious solution appears.

One Long String vs. Object

Nobody needs websites if they are not online. This is why people spend a huge amount of time pretending to be sonar operators on a submarine and "pinging" the availability of their servers (yes, that's why it's called that).

While the output of the Ping command is useful (and you can use ping just as well in the PowerShell console), at the end of the day it's just a big, long string—a series of letters and numbers with some breaks in between.

PowerShell has a command that is similar to Ping, but returns data in a structured manner. This is the Test-Connection command.

Below is the result of this command exchanging packets with the 'DC' server in a completely different, completely structured form:

Not to mention that it's a lot easier to read, but the main thing is that you can now pass this information to the input of another team, make it even more useful (our full video course is designed for this), or simply customize it so that it made more sense.

Built-in help

Up to this point we've been focused on running specific commands using Tab padding, but once you start working with PowerShell more and more commands become more complex with even more complex parameters. While the Verb-Noun syntax helps, it helps even more to have:

1. Current documentation
2. Abundance of examples

Help with Cmdlets

In practice, you should combine Get-Command (to find what you should use) and then use Get-Help to find out how to use that particular command.

A practical example of how to do this: let's say you need to determine all the running Windows services on a computer.

To get started, you can look for commands to interact with services:

Get-Command service
Which will tell you right away that you are on the right track. As you consider returning to the standard PowerShell Verb-Noun command syntax, you'd like to figure out how to properly use the 'Get-Service' command.

Microsoft documentation on the Get-Service command
To do this, use the ‘Get-Help’ command. Start typing
“Get-Help -” and then press the Tab key
You'll quickly discover the available options, with "Name" being the most obvious one, so it's worth a try:

Get-Help -Name Get-Service
You will immediately receive the full command syntax (and which options you can include or exclude based on filters).

If you want to explore the command further and drill down to each parameter, type:

Get-Help -Name Get-Service - Parameter Name

Help with PowerShell examples

We are all human and, no offense to Google bot, we all have our own psychological obstacles that we need to overcome when learning something unfamiliar and bring it into a form that we understand in order to accomplish what we need.

By entering “-examples” or adding the “-detail” flag to the “Get-Help” command, you will be given a set of examples to use the command.
For example, here is the output for the command:

Get-Help -Name Get-Service -Examples

Staying Informed

What could be worse than a broken example, or an example with an error in the documentation. This is often due to either outdated documentation, incorrect examples, or updated libraries.

To work around these problems and get new examples and fixes at the same time, enter:

Update-help
and the process of downloading the updated contextual help will begin.

You can help and transfer some funds for the development of the site

Working in the PowerShell shell, we have not yet thought about how the system generates the lines of text that are displayed on the screen as a result of executing a particular command (remember that PowerShell cmdlets return .NET objects, which, as a rule, do not know how display yourself on the screen).

In fact, PowerShell has a database (a collection of XML files) that contains default formatters for various types of .NET objects. These modules determine which object properties are displayed in the output and in what format: list or table. When an object reaches the end of the pipeline, PowerShell determines its type and looks for it in the list of objects that have a formatting rule defined. If this type is found in the list, then the corresponding formatter is applied to the object; if not, then PowerShell simply displays the properties of that .NET object.

PowerShell can also explicitly set rules for formatting data output from cmdlets, and, like the Cmd.exe command interpreter, redirect this data to a file, to a printer, or to a blank device.

Formatting the output information

In traditional shells, commands and utilities themselves format the output. Some commands (for example, dir in the Cmd.exe interpreter) allow you to customize the output format using special parameters.

In PowerShell, output is formatted by only four special Format cmdlets (Table 17.3). This makes it easier to learn because you don't have to remember formatting options for other commands (other cmdlets don't format output).

Table 17.3. PowerShell Cmdlets for Output Formatting
Cmdlet Description
Format-Table Formats the command output as a table whose columns contain object properties (calculated columns can also be added). Supports the ability to group output data
Format-List The output is formatted as a list of properties, with each property appearing on a new line. Supports the ability to group output data
Format-Custom A custom view is used to format the output.
Format-Wide Formats objects as a wide table that displays only one property per object

As noted above, if none of the Format cmdlets are explicitly specified, the default formatter is used, which is determined by the type of data being displayed. For example, when you run the Get-Service cmdlet, the data defaults to a table with three columns (Status, Name, and DisplayName):

PS C:\> Get-Service Status Name DisplayName ------ ---- ----------- Stopped Alerter Announcer Running ALG Application Level Gateway Service Stopped AppMgmt Application Management Stopped aspnet_state ASP.NET State Service Running Ati HotKey Poller Ati HotKey Poller Running AudioSrv Windows Audio Running BITS Background Intelligent Per... Running Browser Computer Browser Stopped cisvc Indexing Service Stopped ClipSrv Exchange Folder Server Stopped clr_optimizatio... .NET Runtime Optimization Service v... Stopped COMSysApp System application COM+ Running CryptSvc Cryptography services Running DcomLaunch Launching server processes DCOM Running Dhcp DHCP client...

To change the format of the output data, you need to pipe it to the appropriate Format cmdlet. For example, the following command will list services using the Format-List cmdlet:

PS C:\> Get-Service | Format-List Name: Alerter DisplayName: Announcer Status: Stopped DependentServices: () ServicesDependedOn: (LanmanWorkstation) CanPauseAndContinue: False CanShutdown: False CanStop: False ServiceType: Win32ShareProcess Name: ALG DisplayName: Application Level Gateway Service Status: Running DependentServices: () ServicesDependedOn : () CanPauseAndContinue: False CanShutdown: False CanStop: True ServiceType: Win32OwnProcess . . .

As we can see, the list format displays more information about each service than the table format (instead of three columns of data about each service, the list format displays nine rows of data). However, this does not mean that the Format-List cmdlet retrieves additional information about the services. This data is contained in the objects returned by the Get-Service cmdlet, but the default Format-Table cmdlet discards it because it cannot display more than three columns.

When formatting output using the Format-List and Format-Table cmdlets, you can specify the names of the object properties that should be displayed (recall that the Get-Member cmdlet discussed earlier allows you to view the list of properties that an object has). For example:

PS C:\> Get-Service | Format-List Name, Status, CanStop Name: Alerter Status: Stopped CanStop: False Name: ALG Status: Running CanStop: True Name: AppMgmt Status: Stopped CanStop: False . . .

You can display all the properties that objects have using the * parameter, for example:

PS C:\> Get-Service | Format-table *

Redirecting Output Information

PowerShell has several cmdlets that you can use to control your output. These cmdlets start with the word Out and can be seen as follows:

PS C:\> Get-Command out-* | Format-Table Name Name ---- Out-Default Out-File Out-Host Out-Null Out-Printer Out-String

By default, the output information is passed to the Out-Default cmdlet, which in turn delegates all the work of displaying strings to the Out-Host cmdlet. To understand this mechanism, you need to take into account that the PowerShell architecture implies a distinction between the shell core itself (the command interpreter) and the main application (host) that uses this core. In principle, the main application can be any application that implements a number of special interfaces that allow you to correctly interpret the information received from PowerShell. In our case, the main application is the console window in which we work with the shell, and the Out-Host cmdlet passes the output to this console window.

The Paging parameter of the Out-Host cmdlet, like the more command of the Cmd.exe interpreter, allows you to organize page-by-page output of information, for example:

Get-Help Get-Process –Full | Out-Host-Paging

Saving data to a file

The Out-File cmdlet allows you to direct the output to a text file instead of a console window. The redirection operator (>) solves a similar problem, but the Out-File cmdlet has several additional parameters that allow you to more flexibly control the output: set the file encoding type (Encoding parameter), set the length of the output lines in characters (Width parameter), select the mode overwriting the file (parameters Append , noClobber ). For example, the following command will send information about the services registered on the computer to the file C:\service.txt, and this file will be written in ASCII format.

Despite the fact that PowerShell is a console language, sometimes it is necessary to notify the user from a PowerShell script about a certain event or the need to perform a certain action. For example, display a notification about the completion of a long-term PoSh script, or about the occurrence of some important event.

The easiest way to display a window with a custom test is through the Windows scripting subsystem - Wscript.

The following code will display a regular text box with the required text and an OK button.

$wshell = New-Object -ComObject Wscript.Shell
$Output = $wshell.Popup("Report generation script completed")

Using the various properties of the Popup method, you can customize the appearance of the modal message box. You can also return the results of the user's answer to a question (Yes/No) to the script.

$Output = $wshell.Popup("The report generation script is complete! Do you want to display it on the screen?",0,"Report ready",4+32)

General syntax and parameters of the Popup method:

Popup( ,,,<Type>) </b></p><p>Options:</p><ul><li><Text>— string, message text.</li><li><SecondsToWait>- optional, number. The number of seconds after which the window will automatically close.</li><li><Title>- optional, string. Message box title text.</li><li><Type>- optional, number. The combination of flags determines the type of buttons and icon. Possible flag values: <ul><li>0 — OK button.</li><li>1 - OK and Cancel buttons.</li><li>2 - buttons Stop, Repeat, Skip.</li><li>3 - buttons Yes, No, Cancel.</li><li>4 — Yes and No buttons.</li><li>5 — Redo and Cancel buttons.</li><li>16 — Stop icon.</li><li>32 - Question icon.</li><li>48 - Exclamation icon.</li><li>64 - Information icon.</li> </ul></li> </ul><p>Description: Returns an integer value that can be used to determine which button was pressed by the user. Possible values:</p><ul><li>-1 — timeout.</li><li>1 - OK button.</li><li>2 — Cancel button.</li><li>3 — Stop button.</li><li>4 - Repeat button.</li><li>5 — Skip button.</li><li>6 - Yes button.</li><li>7 - No button.</li> </ul><p>More attractive and visually pleasing balloons can be displayed in Windows 7, 8.1 and 10 through the Windows Forms API. The following PowerShell code will display a toast message next to the Windows 10 notification bar, which will automatically disappear after 10 seconds.</p><p>Add-Type -AssemblyName System.Windows.Forms <br>$global:balmsg = New-Object System.Windows.Forms.NotifyIcon <br>$path = (Get-Process -id $pid).Path <br>$balmsg.Icon = ::ExtractAssociatedIcon($path) <br>$balmsg.BalloonTipIcon = ::Warning <br>$balmsg.BalloonTipText = "This is the text of the balloon message for a Windows 10 user" <br>$balmsg.BalloonTipTitle = "Attention $Env:USERNAME"!} <br>$balmsg.Visible = $true <br>$balmsg.ShowBalloonTip(10000)</p><p><img src='https://i0.wp.com/winitpro.ru/wp-content/uploads/2018/10/vsplyvayushee-uvedomlenie-v-powershell.png' width="100%" loading=lazy loading=lazy></p><p>In addition, to create colorful pop-up messages in Windows 10 (PowerShell 5.0+), you can use the separate PowerShell module BurntToast from the PowerShell gallery.</p><p>The module is installed from the online repository using: <br>Install-Module -Name BurntToast</p><p>Now, for example, you can add a colorful notification to the previously discussed one:</p><p>New-BurntToastNotification -Text "Disconnected from the Wi-Fi network", "You have been disconnected from the Wi-Fi network because your device was connected to a high-speed Ethernet connection." -AppLogo C:\PS\changenetwork.png</p><p>So, now you know how to display a user notification via PowerShell. If the user has speakers, you can even play a tune for them:</p><p>::beep(440,500) <br>::beep(440,500) <br>::beep(440,500) <br>::beep(349,350) <br>::beep(523,150) <br>::beep(440,500) <br>::beep(349,350) <br>::beep(523,150) <br>::beep(440,1000) <br>::beep(659,500) <br>::beep(659,500) <br>::beep(659,500) <br>::beep(698,350) <br>::beep(523,150) <br>::beep(415,500) <br>::beep(349,350) <br>::beep(523,150) <br>::beep(440,1000) <br>::beep(880,500) <br>::beep(440,350) <br>::beep(440,150) <br>::beep(880,500) <br>::beep(830,250) <br>::beep(784,250) <br>::beep(740,125) <br>::beep(698,125) <br>::beep(740,250) <br>::beep(455,250) <br>::beep(622,500) <br>::beep(587,250) <br>::beep(554,250) <br>::beep(523,125) <br>::beep(466,125) <br>::beep(523,250) <br>::beep(349,125) <br>::beep(415,500) <br>::beep(349,375) <br>::beep(440,125) <br>::beep(523,500) <br>::beep(440,375) <br>::beep(523,125) <br>::beep(659,1000) <br>::beep(880,500) <br>::beep(440,350) <br>::beep(440,150) <br>::beep(880,500) <br>::beep(830,250) <br>::beep(784,250) <br>::beep(740,125) <br>::beep(698,125) <br>::beep(740,250) <br>::beep(455,250) <br>::beep(622,500) <br>::beep(587,250) <br>::beep(554,250) <br>::beep(523,125) <br>::beep(466,125) <br>::beep(523,250) <br>::beep(349,250) <br>::beep(415,500) <br>::beep(349,375) <br>::beep(523,125) <br>::beep(440,500) <br>::beep(349,375) <br>::beep(261,125) <br>::beep(440,1000)</p> <p>While writing a program or script, any novice programmer will encounter a problem where he needs to repeat the code twice and this can help <b>functions in Powershell</b>. Functions are also called methods and procedures. In addition to their repeated use, they are also useful for distinguishing one part of the script from another, even though it is executed only once. The methods described below exist in many languages ​​and work in a similar scenario.</p> <h2>Creation</h2> <p>Let's imagine that every morning you check the last 50 logs for 14 hours of Application log using this command:</p><p>Get-EventLog -LogName Application -Newest 50 | where TimeWritten -ge (Get-Date).AddHours(-14)</p><p><img src='https://i2.wp.com/fixmypc.ru/media/uploads/2019/10/10/1.jpg' width="100%" loading=lazy loading=lazy>The command is not very complicated, but soon you will get tired of writing it. To reduce this work, it can be separated into a separate function:</p><p>Function Get-DayLog ( Get-EventLog -LogName Application -Newest 50 | where TimeWritten -ge (Get-Date).AddHours(-14) )</p><p>Any function must consist of three things:</p> <ul><li>function - announces and says that there will be a name after it;</li> <li>function name - the name by which we will call it. In our case, the name is Get-DayLog;</li> <li>parentheses indicate the beginning and end of an expression.</li> </ul><p>After writing a function, it is called by name:</p><p>Get-DayLog</p><p><img src='https://i0.wp.com/fixmypc.ru/media/uploads/2019/10/10/2.jpg' width="100%" loading=lazy loading=lazy></p> <p>Considering that we may need to receive data not for the last 14 hours and for more than 50 days, we may need to change it by passing the parameters.</p> <h2>Naming</h2> <p>It is not necessary to use the same plan name as is customary in Powershell, that is, instead of “Get-DayLog” you can write “daylog”. This approach is recommended and is a common practice, which will help distinguish the launch of a third-party program from a function.</p> <p>Functions in Powershell are always named as follows. The first word is verbs like:</p> <ul><li>Get - receive;</li> <li>Set - change;</li> <li>Install - install;</li> <li>New - create.</li> </ul><p>The second name is a noun, as in the case above DayLog. Microsoft has an approved list of verbs that is available here in English. If you do not adhere to these rules and want to add your function (cmdlet or module) to one of the repositories, then it may not pass moderation.</p> <h2></h2> <h2>Passing parameters</h2> <p>Most often, functions take an object and return it. For example, you may need to change the time when these logs are created and their number. The existing function does not have this option. You can edit the code every time, but this is not a programmer's approach. For such an opportunity to appear in the function, you need to add parameters that it will accept:</p><p>Function Get-DayLog ($param1,$param2) ( Get-EventLog -LogName Application -Newest $param1 | where TimeWritten -ge (Get-Date).AddHours($param2) )</p><p>Function parameters are indicated in parentheses and written after the function name and before the expression.</p> <p>Now, to call a function, you need to pass two parameters:</p><p>Get-DayLog -param1 50 -param2 -14</p><p><img src='https://i1.wp.com/fixmypc.ru/media/uploads/2019/10/10/4.jpg' width="100%" loading=lazy loading=lazy></p> <p>When calling a function, we pass two required parameters with values. These values, inside the function, will be available under the names $param1 and $param2. We pass these variables to the command for receiving and filtering logs.</p> <h3>Setting Defaults</h3> <p>In our task, most often, we receive only the last 50 logs and we do not want to specify them every time. If we do not specify this parameter in an existing function, we will get an error. To avoid this, you need to specify a default value. In the example below, I have set $param1 to 50. This will only be used if we do not use this parameter in the call:</p><p>Function Get-DayLog ($param1=50,$param2) ( Get-EventLog -LogName Application -Newest $param1 | where TimeWritten -ge (Get-Date).AddHours($param2) ) Get-DayLog -param2 -7</p><p><img src='https://i0.wp.com/fixmypc.ru/media/uploads/2019/10/10/5.jpg' width="100%" loading=lazy loading=lazy></p> <p>We must always specify the param2 key, which adds a bit of work. To fix this, just swap them:</p><p>Function Get-DayLog ($param2,$param1=50) ( Get-EventLog -LogName Application -Newest $param1 | where TimeWritten -ge (Get-Date).AddHours($param2) ) Get-DayLog -7 1 Get-DayLog -7</p><p><img src='https://i0.wp.com/fixmypc.ru/media/uploads/2019/10/10/7.jpg' width="100%" loading=lazy loading=lazy></p> <p>As can be seen in the example, if we do not specify the keys param1 and param2, the sequence is important, since it is in this sequence that they will be assigned to variables inside functions.</p> <h3>Returning values</h3> <p>Unlike other languages, if we assign the $result variable to the result of the Get-DayLog function, it will contain the values:</p><p>$result = Get-DayLog -7 1</p><p>This will work until we decide to change the function by assigning variables:</p><p>Function Get-DayLog ($param2,$param1=50) ( $events = Get-EventLog -LogName Application -Newest $param1 | where TimeWritten -ge (Get-Date).AddHours($param2) ) $result = Get-DayLog -7 $result $events</p><p>We cannot get the result using the $result variable, since the function does not output information, but stores it in the $events variable. By calling $events we also do not receive information, since the concept of “variable visibility” works here.</p> <p>Since functions are a separate part of the program, all logic and its variables should not touch another part of it. The scope of variables implies the same. All variables created inside a function remain within it. This situation can be corrected using return:</p><p>Function Get-DayLog ($param2,$param1=50) ( $events = Get-EventLog -LogName Application -Newest $param1 | where TimeWritten -ge (Get-Date).AddHours($param2) return $events ) $result = Get-DayLog -7 $result</p><p><img src='https://i0.wp.com/fixmypc.ru/media/uploads/2019/10/10/11.jpg' width="100%" loading=lazy loading=lazy></p> <p>I would recommend always returning values ​​using return rather than using output using commands like Write-Output inside a function. Using return stops the function and returns a value, which means that it should not be placed in the middle of the logic if it was not intended to be so.</p> <p>There can be several return values. For example, let's create a function that will calculate salary and tax:</p><p>Function Get-Salary ($Zarplata) ( $nalog = $Zarplata * 0.13 $zarplata_bez_nds = $Zarplata - $nalog return $nalog,$zarplata_bez_nds ) Get-Salary -Zarplata 100000</p><p>I returned both values ​​separated by a comma. By default, an array is always returned. this is a set of unnamed parameters. We have already written about them in more detail.</p> <p>In the case of arrays, to add an inscription about salary and tax, you need to use indexes:</p><p>$result = Get-Salary -Zarplata 100000 # Define the data type $result.GetType() Write-Host "this is a salary" $result Write-Host "this is a tax" $result</p><p><img src='https://i2.wp.com/fixmypc.ru/media/uploads/2019/10/10/13.jpg' width="100%" loading=lazy loading=lazy></p> <p>Any data type can be returned. For example, we can use another data type, hash tables, which, unlike arrays, are named:</p><p>Function Get-Salary ($Zarplata) ( $nalog = $Zarplata * 0.13 $zarplata_bez_nds = $Zarplata - $nalog return @("Tax"=$nalog;"Salary"=$zarplata_bez_nds;) ) Get-Salary -Zarplata 100000</p><p><img src='https://i1.wp.com/fixmypc.ru/media/uploads/2019/10/10/14.jpg' width="100%" loading=lazy loading=lazy></p> <h2>Using Arrays</h2> <h3>Passing arrays as parameters</h3> <p>In previous articles there were many examples of working with arrays and hash tables. We can pass them, like any other data type, to a function. As an example, all Powershell commands that have the ComputerName key can be executed remotely. Most of these commands can take arrays as values, which means we don't have to pass computer names one by one.</p> <p>The function will accept an array of computer names and return all stopped services. I will also declare this type strict, for clarity, although it will work without it anyway:</p><p>Function Get-ServiceStopped ($Computers)( $services = Get-Service -ComputerName $Computers | where Status -eq Stopped return $services ) Get-ServiceStopped "127.0.0.1","localhost"</p><p><img src='https://i0.wp.com/fixmypc.ru/media/uploads/2019/10/10/19.jpg' width="100%" loading=lazy loading=lazy></p> <p>Arrays also work by index, which allows you to pass more parameters. This method is not relevant, but may come in handy someday.</p><p>Function Get-ServiceStopped ($Computers)( $services = Get-Service -ComputerName $Computers | where Status -eq $Computers[-1] return $services ) Get-ServiceStopped "127.0.0.1","localhost","Stopped"</p><h3>Hash tables</h3> <p>Hash table parameters can be passed not just to a function, but as cmdlet parameters. Let's add to our function to start the service if it is stopped:</p><p>Function Get-ServiceStopped ($Params)( $services = Get-Service @Params | where Status -eq Stopped $services = Start-Service $services return $services ) Get-ServiceStopped @(Name="WinRM";ComputerName=@( "127.0.0.1","localhost"))</p><p>The @ sign in the command declares that the hash table data will be used as command parameters. It is important that their names correspond to these parameters.</p> <h2>Conditions</h2> <p>There are no restrictions on the use of the terms. This can be quite convenient when a function must return different values.</p> <h3></h3> <p>Below is an example where, depending on the loading speed of the main part of the site, a different response will be returned. If a response speed of less than 76 milliseconds is normal, a longer response will return a different result:</p><p>Function Get-SiteResponse ( # Start of counting $start_time = Get-Date # Execute the request $request = Invoke-WebRequest -Uri "https://site" # Record the end of execution $end_time = Get-Date # Calculate the time difference $result = $end_time - $start_time # Check and return the result if ($result.Milliseconds -lt 76) ( return "The response speed is normal " + $result.Milliseconds) else( return "The site takes a long time to respond " + $result.Milliseconds ) ) Get- SiteResponse</p><p><img src='https://i1.wp.com/fixmypc.ru/media/uploads/2019/10/11/20.jpg' width="100%" loading=lazy loading=lazy></p> <h3>Switch</h3> <p>We have already talked about it in previous articles. In short, these are more convenient conditions. Using the previous example but with Switch, it would look like this:</p><p>Function Get-SiteResponse ( # Start of counting $start_time = Get-Date # Execute the request $request = Invoke-WebRequest -Uri "https://site" # Record the end of execution $end_time = Get-Date # Calculate the time difference $result = $end_time - $start_time # Check and return the result switch($result.Milliseconds) ( ($PSItem -le 76) ( return "The response speed is normal " + $result.Milliseconds) default ( return "The site takes a long time to respond " + $result. Milliseconds ) ) ) Get-SiteResponse</p><p><img src='https://i1.wp.com/fixmypc.ru/media/uploads/2019/10/11/21.jpg' width="100%" loading=lazy loading=lazy>Another example of Switch is calling a function depending on the passed parameters. In the example below, I'm calling the function that contains the Switch. To this function I pass the computer name, which is checked for mention of the specified phrases and calls the appropriate function. Each function that sets updates returns a value to Switch, and then returns inside it:</p><p>Function Install-SQLUpdates ( # doing the installation return "Installation of updates on the SQL server was successful" ) function Install-ADUpdates ( # doing the installation return "Installation of updates on the AD server was successful" ) function Install-FileServerUpdates ( # doing the installation return "Installation of updates to the file server was successful" ) function Make-Switch ($computer) ( # Checking the computer name $result = switch($computer)( ($computer -like "SQL*") (Install-SqlUpdates) ($computer -like " AD*") (Install-ADUpdates) ($computer -like "FileServer*") (Install-FileServerUpdates) default ("There is no such type of computer") ) return $result ) Make-Switch "AD1"</p><p><img src='https://i1.wp.com/fixmypc.ru/media/uploads/2019/10/11/22.jpg' width="100%" loading=lazy loading=lazy></p> <p>With switch it is also convenient to pass Boolean values. In the example below, if the -On key is specified, the service will turn on, and if it is not there, it will turn off:</p><p>Function Switch-ServiceTest ($on) ( if ($on) (Write-Output "Service on") else ("Service off") ) Switch-ServiceTest -On Switch-ServiceTest</p><p><img src='https://i1.wp.com/fixmypc.ru/media/uploads/2019/10/11/26.jpg' width="100%" loading=lazy loading=lazy></p> <h2>Transfer via conveyor or Pipeline</h2> <p>You've probably worked through Powershell commands that allow you to use a pipeline like this:</p><p>Get-Process -Name *TestProc* | Stop-Process</p><p>If we want to use the approach described above, creating new commands as functions, then the pipeline will not work:</p><p>Function Get-SomeNum ( # Generate a number $num = Get-Random -Minimum 5 -Maximum 10 return $num ) function Plus-SomeNum ($num) ( Write-Host "Adding a number " $num $num += $num return $ num ) Get-SomeNum Plus-SomeNum 5 Get-SomeNum | Plus-SomeNum</p><p><img src='https://i0.wp.com/fixmypc.ru/media/uploads/2019/10/12/35.jpg' width="100%" loading=lazy loading=lazy></p> <p>By running the following command we can see that values ​​that can be received through the pipeline are marked with a special attribute:</p><p>Get-Help Stop-Process -Parameter Name</p><p>There are only two such attributes:</p> <ul><li><b>ValueFromPipelineByPropertyName</b>- getting a value from the pipeline by name;</li> <li><b>ValueFromPipeline</b>- receiving only the value through the pipeline.</li> </ul><p>In addition, inside our function, we must add a special Process block. Our script will ultimately look like this:</p><p>Function Get-SomeNum ( $num = Get-Random -Minimum 5 -Maximum 10 return $num ) function Plus-SomeNum ( Param ( $num) process ( Write-Host "Adding a number " $num $num += $num return $ num ) ) 1..5 | Plus-SomeNum Get-SomeNum | Plus-SomeNum</p><p><img src='https://i1.wp.com/fixmypc.ru/media/uploads/2019/10/12/37.jpg' width="100%" loading=lazy loading=lazy></p> <p>A function extension attribute that adds some functionality to functions allowing them to work as a command.</p> <p>If we had not specified the Process block, the function would have returned only the last result from the array 1..5:</p> <p><img src='https://i0.wp.com/fixmypc.ru/media/uploads/2019/10/12/39.jpg' width="100%" loading=lazy loading=lazy></p> <p>If our commands will be critical in nature, such as deletion, or multiple values ​​may be passed through the pipeline, then it is worth using the ValueFromPipelineByPropertyName attribute. This way we will prevent random values ​​from getting through the pipeline. In the example below I changed</p><p>Function Get-SomeNum ( $num = Get-Random -Minimum 5 -Maximum 10 $object = @(num=$num) return $object ) function Plus-SomeNum ( Param ( $num) process ( Write-Host "Adding a number " $num $num += $num return $num ) ) Get-SomeNum | Plus-SomeNum @(num=5) | Plus-SomeNum @(bad=5) | Plus-SomeNum</p><p><img src='https://i1.wp.com/fixmypc.ru/media/uploads/2019/10/12/40.jpg' width="100%" loading=lazy loading=lazy></p> <p>As already written, ValueFromPipelineByPropertyName accepts only named parameters and in the case of the name “bad” we get an error:</p> <ul><li><span>Cannot bind an input object to any command parameters because the command does not accept pipeline input</span></li> <li><span>The input object cannot be bound to any parameters for the command either because the command does not take pipeline input or the input and its properties do not match any of the parameters that take pipeline input.</span></li> </ul><p>Moreover, we cannot pass named parameters through a table hash, only through pscustomobject.</p> <p>You can specify two attributes at once like this:</p><p>This will allow you to use a value with a name, if it is specified, or without it. This will not save you from the situation if you pass a parameter with a different name:</p> <p><img src='https://i2.wp.com/fixmypc.ru/media/uploads/2019/10/12/41.jpg' width="100%" loading=lazy loading=lazy></p> <h3>Passing Multiple Values ​​Through a Pipeline</h3> <p>For example, consider a situation where we need to pass two values ​​through a pipeline. If Get-SomeNum returns an array, then we will have each number go through the pipeline separately. This is another reason to use named parameters:</p><p>Function Get-SomeNum ( $number1 = Get-Random -Minimum 5 -Maximum 10 $number2 = Get-Random -Minimum 1 -Maximum 5 $object = @(num1=$number1;num2=$number2) return $object ) function Plus -SomeNum ( Param ( $num1, $num2) begin ($num1 += $num1 $num2 = $num2 * $num2) process ( return @("Addition result"=$num1; "Multiplication result"=$num2) ) ) Get-SomeNum | Plus-SomeNum</p> <script>document.write("<img style='display:none;' src='//counter.yadro.ru/hit;artfast_after?t44.1;r"+ escape(document.referrer)+((typeof(screen)=="undefined")?"": ";s"+screen.width+"*"+screen.height+"*"+(screen.colorDepth? screen.colorDepth:screen.pixelDepth))+";u"+escape(document.URL)+";h"+escape(document.title.substring(0,150))+ ";"+Math.random()+ "border='0' width='1' height='1' loading=lazy loading=lazy>");</script> </div><div class="clear"></div> <script type="text/javascript"> document.getElementById('hc_full_comments').innerHTML = ''; </script><br /><br /><noindex><p align="center"><center> <div id="meta_news_block1111" style="text-align: center;"></div></center> </p> <br /><br /> <p align="center"> </p> </noindex> </div> </div> <div id="sidebar"> <div class="clear"></div><br /> <h2 class="front" style="margin:15px 0 5px 0">Popular articles</h2> <div class="tabcont"> <ol> <li><a href="https://gtavrl.ru/en/kak-skopirovat-soobshchenie-v-vk-kak-pereslat-soobshchenie-drugomu/">How to forward a message to another person on VKontakte</a></li> <li><a href="https://gtavrl.ru/en/pochemu-ne-rabotaet-kontakt-pochemu-ne-rabotaet-prilozhenie/">Why doesn't the VKontakte application work?</a></li> <li><a href="https://gtavrl.ru/en/chto-nado-nazhat-chtoby-istoriya-ne-sohranyalas-kak-sdelat-chtoby-ne-sohranyalas-istoriya-kak-udalit/">How can I prevent history from being saved?</a></li> <li><a href="https://gtavrl.ru/en/fotoredaktor-sketch-karikatury-delaem-karikaturu-iz-fotografii-v/">Making a caricature from a photograph in Photoshop</a></li> <li><a href="https://gtavrl.ru/en/otklyuchit-fonovye-prilozheniya-android-apk-editor-uvelichivaem/">Increasing smartphone performance</a></li> </ol> </div> <h2 class="front" style="margin:15px 0 5px 0">Latest articles</h2> <div class="tabcont"> <ol> <li><a href="https://gtavrl.ru/en/vyhod-samsung-galaxy-note-5-samsung-galaxy-note5---tehnicheskie-harakteristiki-informaciya-o/">Samsung Galaxy Note5 - Specifications</a></li> <li><a href="https://gtavrl.ru/en/kak-bystro-uznat-svoi-nomer-mts-kak-bystro-uznat-svoi-nomer-mts-komanda/">How to quickly find out your MTS number Team at MTS find out your phone number</a></li> <li><a href="https://gtavrl.ru/en/kak-popolnit-schet-drugomu-abonentu-bilain-so-svoego-balansa/">Transferring money between Beeline subscribers: available ways to Top up from your Beeline balance</a></li> <li><a href="https://gtavrl.ru/en/tarif-moi-bezlimit-tele2-opisanie-podklyuchenie-i-stoimost-opcii/">Mobile unlimited options on Tele2 What is unlimited Internet on Tele2</a></li> <li><a href="https://gtavrl.ru/en/pochemu-telefon-otklyuchilsya-i-bolshe-ne-vklyuchaetsya-chto-delat/">What to do if the phone does not turn on?</a></li> <li><a href="https://gtavrl.ru/en/test-draiv-golosovogo-pomoshchnika-alisa-ot-yandeksa-golosovoi-pomoshchnik-alisa/">Voice assistant Alice: download for Android Yandex voice assistant Alice download for Android</a></li> <li><a href="https://gtavrl.ru/en/skachat-prilozhenie-russko-angliiskii-perevodchik-besplatnye/">Free programs for Windows download for free</a></li> </ol> </div> <div class="widget" id="ajdg_grpwidgets-3"> <div class="g g-9"> <div class="g-single a-27"> <script> jQuery(function() { window.onscroll = function() { height_scroll = jQuery(document).scrollTop(); height = jQuery(document).height(); height50 = height / 2; if (height_scroll >= height50) { jQuery("#site-code-block-22").fadeIn(1200); document.getElementById('site-code-block-22').style.display = 'block'; jQuery("#site-code-block-23").fadeOut(1200); document.getElementById('site-code-block-23').style.display = 'none'; } else { jQuery("#site-code-block-22").fadeOut(1200); document.getElementById('site-code-block-22').style.display = 'none'; document.getElementById('site-code-block-23').style.display = 'block'; jQuery("#site-code-block-23").fadeIn(1200); } }; }); </script> <div class="site-code-block prma-count" data-rel="cb_23" id="site-code-block-23" style=""> </div> <div class="site-code-block prma-count" data-rel="cb_22" id="site-code-block-22" style=""> </div> </div> </div> </div> <div class="clear"></div> <br /> <center> <div style="color: #333333; font-size: 11px;"> </div> </center> <div class="clear"></div> </div> <div class="clear"></div> </div> </div> </div>  <br /><br /> <div id="footeri"> <div id="footer"> <div class="footer-sec"> <h6>Sections</h6> <ul> <li><a href="https://gtavrl.ru/en/category/youtube/">Youtube</a></li> <li><a href="https://gtavrl.ru/en/category/facebook/">Facebook</a></li> <li><a href="https://gtavrl.ru/en/category/twitter/">Twitter</a></li> <li><a href="https://gtavrl.ru/en/category/tips/">Adviсe</a></li> <li><a href="https://gtavrl.ru/en/category/useful-tips/">Useful tips</a></li> <br /> </ul> </div> <div class="footer-sec"> <h6>Pages</h6> <ul> <li><a href="">about the project</a></li> <noindex> <li><a href="" >RSS news</a></li> </noindex> </ul><br /><br /><br /> <h6>Special projects</h6> <ul> <li><a href="https://gtavrl.ru/en/feedback/">Connect with us</a></li> </ul> </div> <div id="footer-top"> <h6>Contacts</h6> <ul> <li><a href="">Advertising on the website</a></li> <li><a href="https://gtavrl.ru/en/feedback/">Contacts</a></li> </div> <div class="clear"></div> </div></div> <div id="bottom"><div class="foot_col1">2024 <a href="https://gtavrl.ru/en/">gtavrl.ru</a>. </div> <script type="text/javascript">var addthis_config = { "data_track_addressbar":true,"pubid": "ra-58b68bb0f1371607"} ;addthis_config.data_track_addressbar = false;addthis_config.data_track_clickback = false;</script> <script type='text/javascript'> var flag_hide = 0; function hide_direct() { flag_hide = 1; jQuery('#rek_mob_fixed').slideToggle( 'slow' ); var date = new Date(); var expires_hour = 21600000; date.setTime(date.getTime()+expires_hour); showSocial(); Cookies.set('advp_show_me', '1', { expires: date, path: '/'} ); } ; jQuery(function(f){ var element = f('#rek_mob_fixed'); element.delay(8000); f(window).scroll(function(){ if (flag_hide == 0){ var offset_element_for_hide = jQuery('#before_footer').val(); if (offset_element_for_hide != null) { offset_element_for_hide = jQuery('#before_footer'); offset_element_for_hide = jQuery(offset_element_for_hide).offset().top - jQuery(window).height(); } else { offset_element_for_hide = jQuery(document).height(); } //Если рекламный блок более 1000px по ширине, устанавливай фикс. ширину 1000px if (jQuery('#rek_mob_fixed_block').actual('width') >1000) { jQuery('#rek_mob_fixed_block').css({ 'max-width':'1000px'} ); } if(f(this).scrollTop() > 500){ element.fadeIn(0); } if(f(this).scrollTop() < 500 || f(this).scrollTop() > offset_element_for_hide ){ element.fadeOut(0) } if(f(this).scrollTop() + f(this).height() >= f(document).height() && flag_hide == 0 && jQuery('#rek_mob_fixed').is(':visible')) { jQuery('#rek_mob_fixed').slideToggle(100); } } } ); } ); function showSocial(){ if(flag_hide == 1 ) jQuery('#footer-share').slideToggle('slow'); } </script><div id="wondergridgallerylightbox_options" data-skinsfoldername="skins/default/" data-jsfolder="/wp-content/plugins/modesco-wonderplugin-gridgallery/engine/" style="display:none;"></div> <script type='text/javascript' src='https://gtavrl.ru/wp-content/plugins/contact-form-7/includes/js/scripts.js?ver=4.9.2'></script> <script type='text/javascript' src='https://gtavrl.ru/wp-content/plugins/modesco-monica/script.min.js?ver=4.9.1'></script> <script type='text/javascript'> /* <![CDATA[ */ var tocplus = { "visibility_show":"\u043f\u043e\u043a\u0430\u0437\u0430\u0442\u044c","visibility_hide":"\u0441\u043a\u0440\u044b\u0442\u044c","width":"100%"} ; /* ]]> */ </script> <script type='text/javascript' src='https://gtavrl.ru/wp-content/plugins/modesco-table-of-contents-plus/front.js?ver=1404'></script> <script type='text/javascript' src='https://gtavrl.ru/wp-content/plugins/page-links-to/js/new-tab.min.js?ver=2.9.8'></script> <script type='text/javascript'> var q2w3_sidebar_options = new Array(); q2w3_sidebar_options[0] = { "sidebar" : "ads-sidebar", "margin_top" : 10, "margin_bottom" : 50, "stop_id" : "before_footer", "screen_max_width" : 0, "screen_max_height" : 0, "width_inherit" : false, "refresh_interval" : 1500, "window_load_hook" : false, "disable_mo_api" : false, "widgets" : ['ajdg_grpwidgets-3'] } ; </script> <script type='text/javascript' src='https://gtavrl.ru/wp-content/plugins/q2w3-fixed-widget/js/q2w3-fixed-widget.min.js?ver=5.0.4'></script> <script type='text/javascript' src='https://gtavrl.ru/wp-content/plugins/youtube-embed-plus/scripts/fitvids.min.js?ver=4.9.1'></script> <script type='text/javascript' src='/wp-includes/js/wp-embed.min.js?ver=4.9.1'></script> <script type="text/javascript"> var _hcwp = _hcwp || []; var _hcobj = { widget_id : 29264, widget : "Bloggerstream",selector: '.hc_counter_comments',platform:"wordpress", } ; _hcwp.push(_hcobj); (function() { if("HC_LOAD_INIT" in window)return; HC_LOAD_INIT = true; var lang = "ru"; var hcc = document.createElement("script"); hcc.type = "text/javascript"; hcc.async = true; hcc.src = ("https:" == document.location.protocol ? "https" : "http")+"://w.hypercomments.com/widget/hc/29264/"+lang+"/widget.js"; var s = document.getElementsByTagName("script")[0]; s.parentNode.insertBefore(hcc, s.nextSibling); } )(); </script> </body> </div> </body> </html>