Build on the .NET framework, Windows PowerShell is a task-based command-line shell and scripting language; it is designed specifically for system administrators and power users, to rapidly automate the administration of multiple operating systems (Linux, macOS, Unix, and Windows) and the processes related to the application that run on those operating systems.
PowerShell is an object-oriented automation engine and scripting language with an interactive command-line shell that Microsoft developed to help IT Professionals configure systems and automate administrative tasks.
PowerShell is open-source.
PowerShell can be considered as a “glue” that ties most of Microsoft applications together.
Virtually all the server products Microsoft is producing right now can be managed through PowerShell. From an administrative standpoint, this means that if you become proficient in PowerShell, you will have the skill set necessary for managing most of Microsoft’s newer products.
PowerShell is Object-Based
This gives us incredible flexibility. Filter, sort, measure, group, compare or take other actions on objects as they pass through the pipeline. Work with properties and methods rather than raw text.
PowerShell is easy to adopt, learn and use because it does not require a background in programming.
It’s important to know what we can do in our system. Can we just run any script and brick our system? Or we can only execute commands that are safe?
Windows PowerShell execution policies let you determine the conditions under which Windows PowerShell loads configuration files and run scripts.
You can set an execution policy for the local computer, for the current user, or for a particular session. You can also use a Group Policy setting to set execution policy for computers and users.
Requires that all scripts and configuration files be signed by a trusted publisher, including scripts that you write on the local computer. Prompts you before running scripts from publishers that you have not yet classified as trusted or untrusted.
Does not require digital signatures on scripts that you have written on the local computer (not downloaded from the internet)
Scripting languages like VBScript allows every script to run which is signed, no matter if you trust the authority or not. Even it’s a fake forged signature, it will trust it and get executed. Whereas in PowerShell, only if the signature is from a trusted authority, only then it will work.
Unsigned scripts can run. Warns the user before running scripts and configuration files that are downloaded from the Internet.
Permits individual commands, but will not run scripts.
Nothing is blocked and there are no warnings or prompts. (Unsecure)
To see our current execution policy, use:
Get-ExecutionPolicy
To change the policy
Set-ExecutionPolicy RemoteSigned
Set-ExecutionPolicy RemoteSigned -Force# for avoiding a prompt in ISE
You will have run powershell as an administrator and then run the above command.
If you worried about this command and you just want to check what this command will do then run the following:
Set-ExecutionPolicy RemoteSigned -WhatIf
WhatIf
and Force
are application on all commands, in PowerShell.
In production environments, Execution Policy can be imposed by a Group Policy. We will later understand Group policy but for now, you can think of it as a document, where you write rules or policies and impose them on the machines in a domain automatically.
Execution policy is one major aspect of PowerShell, there are more.
Sample .bat file
@echo off
echo "Spyware and Ransomware code initialized"
echo "All drives are getting encrypted"
echo "This system is not compromised"
pause
1. Association with notepad & not powershell.exe by default You can directly click this .bat script and it will run. Powershell scripts don’t directly run on a double click. They are associated by default to Notepad.
2. Execution policy restrictions Using this we can declare how we want PowerShell scripts to be executed in out system
3. Have to type the explicit path of the script in order to execute it Also, when you are running a script, just the name of the script is not enough, you have to type in the entire path. So you can be protected from malicious scripts in Unix systems where cd
can be a directly writtem. Explain this.
4. Can require script to be signed else will not execute it
5. Can further add restrictions that script should be signed by your trustworthy certificate provider only.
Get-Help
commands provides help about every command available in PowerShell. It provides much more than just the syntax and brief description of the command. This is one of the most useful commands.
All PowerShell commands are named in a fixed pattern, VERB-NOUN. So for example Get-Command
will give you the list of commands.
So say you want to search commands that have “service” in their name. Then use
Get-Command-Name'\*service\*'
The *
is a wildcard character, just means ignore characters after or before it.
To just get the first or last 3 results, you can pipe another command to this.
Get-Command-Name'\*service\*' | Select-Object-First3Get-Command-Name'\*service\*' | Select-Object-Last3
If you want to see help on a particular command, then use:
Get-HelpGet-Service
You will a summary of the help here. If you want to more details, with example usage of the commands etc., then use:
Get-HelpGet-Service-Full
Reading this much documentation in the terminal, is not a good user experience. Use this to open the documentation in the browser:
Get-HelpGet-Service-Online
One of the best ways of reading help documentation is opening it in a dedicated window. You also get search functionality. Use the following:
Get-HelpGet-Service-ShowWindow
The above was all about getting help for a command. But what if you want to get help for a concept like a for-loop or something like ISE. Then you can use the following:
Get-Help"about\*"
The above will give you a list of all the help topics, with about in it. Once you find what you are looking for, you can get get help about it:
Get-Help"about\_Arrays"-ShowWindow
Some other commands
Update-Help
Use this to update the help documentation.
To save help files in a particular path, use the following:
Save-Help C:\\Users\\rst\\Documents\\Training\\PowerShell\\scripts\\test
1. Comment
\# I am single line comment. I will be ignored by PowerShell<#
I am a multiline
comment. I will
be ignored
#>
2. Get the location of the current directory
Get-Location
3. To change directory
Set-Location C:\\Users\\rst\\Downloads
4. To go back
Set-Location ..
5. To get current date
Get-Date
6. List all files and folders at a location
Get-ChildItem
7. Search recursively inside the sub folders
Get-ChildItem-Recurse
8. Get the list of items by path
Get-ChildItem-Path C:\\Users\\rst\\Downloads
9. Print on the console
Write-Output"Print me on the console"
10. Clear your screen
Clear-Host
11. Copy a file
Copy-Item-Path ..\\Notes.md -Destination .
12. Copy everything from source path to destination path
Copy-Item-Path Test\_Folder1\\\* -Destination Test\_Folder2\\ -Recurse
13. Copy everything from source path to destination path except the files inside subfolders
Copy-Item Test_Folder1\* -Destination Test_Folder2
14. Move item from source to destination
Move-Item sample.bat -Destinationtest-folder
15. Move item from source to destination and rename
Move-Item sample.bat -Destinationtest-folder\\sample-bat.bat
16. Rename file or folder
Rename-Item sample.bat -NewName thisisnewname.bat # orRename-Item .\\thisisnewname.bat -NewName"sample hello.bat"Rename-Item .\\test-folder-NewName test\_folder
17. Delete an item
Remove-Item-Path .\\hello.txt
18. Remove a folder
Remove-Item-Path .\\test\_folder -Recurse
19. How to get PowerShell’s help
Get-HelpGet-HelpGet-HelpRemove-Item
20. To get the list of different commands executed in the shell
Get-History
21. Clear the shell’s command history
Clear-History
(https://mgmt.rstforum.net/uploads/media-1701498561127.PNG)
Variables are the names you give to computer memory locations which are used to store values in a computer program.
PowerShell uses variables as temporary, named storage for objects. Variable name begins with $
.
Variables are objects. It is the name of a memory location, where objects are store.
$MyVariable = "Some string value"$My\_Variable1# to view the variable$global:var\_name = "This will be accessible throughout the script"Set-Variable-Name"myVar"-Value"value of the variable"New-Variable-Name"myVar"-Value"value of the variable"
To access any variable, type $
and then the variable name
To get the complete list of variables in PowerShell
Get-Variable
Other important variable related commands
Get-VariableRemove-Variable# Remove-Variable My\_Variable1Clear-Variable# Ex.$My\_Variable1 = "Some string value"Clear-Variable-Name My\_Variable1
$My\_Variable1$My\_Variable1.GetType()
By default, variable name cannot contain spaces and special characters (except a few). However in PowerShell, if you really need you can give any name to the variable
${give any \_name&&\*\*++} = "Value of this variable"${give any \_name&&\*\*++}
A constant is a value that never changes Ex. value of Pi, speed of light, radius of earth
Set-Variable test -Option Constant -Value100Set-Variable test -Option ReadOnly -Value100
Type of data we are storing inside a variable.
You don’t have to explicitly declare the data type of a variable. PowerShell automatically chooses the data type for you when you initialize the variable – that is, when you first assign a value.
Some common data types: String, Integer, Boolean, Double, etc.
$var = "10"$var.GetType()
$var1 = 100$var2 = 205# Sum$sum = $var1 + $var2$sum# Difference$diff = $var2 - $var1$diff# Multiply$multiply = $var2 * $var1$multiply# Difference$divide = $var1 / $var2$divide# Type of variable$sum.GetType()
$var1 = 100$var2 = 205# Sum$sum = $var1 + $var2$sum# Difference$diff = $var2 - $var1$diff# Multiply$multiply = $var2 \* $var1$multiply# Difference$divide = $var1 / $var2$divide# Type of variable$sum.GetType()
$diff.GetType()
$multiply.GetType()
$divide.GetType()
# Modulus Operator$Remainder = $var2 % $var1$Remainder$Remainder = 10 % 6$Remainder
$var\_name = "John"$var\_year = "Year: 2022"$current\_temp = "40"$another\_string\_var = "$var\_name is make a course in $var\_year and current temperature is $current\_temp"$another\_string\_var
Another way of creating String, is to place value inside single quotes. $another_string_var = 'This is also a string
Difference is that single quotes DO NOT resolve the variables to it’s value. Whereas double quotes resolve the variable and you will find only the value to be printed.
\# Single quotes won't print the variable$temperature = 42Write-Output"Temperature : $temperature"Write-Output'Temperature : $temperature'
How to avoid resolving of a variable inside double quotes?
Use escape character (grave-accent(`)) before every variable which you do not want to be resolved.
$another\_string\_var = "$var\_name is make a course in \`$var\_year and current temperature is $current\_temp"$another\_string\_var
$string\_var = "a Random String "$string\_var.Length
$string\_var.Contains("Random")
$string\_var.Contains("random")
$string\_var.IndexOf("Random")
$string\_var.Trim()
$string\_var.ToUpper()
$string\_var.ToLower()
$string\_var.Replace("a", "b")
$string\_var.Replace("Random", "Nice")
here-string How to handle quotes inside string?
We can use here-string
Just need to close our string value inside @" "@
$text = @"
Question: "Who are you?"
Answer: "I am so & so and came here for this purpose"
"@$text$normal = "
I am $age years old
How old are you?
"$normal# I don't want to expand the value of $age, I want to store it as it is$normal = @'
I am $age years old
How old are you?
'@Write-Output$normal
Using
-is
operator
$a\_var = 1000$a\_var-is \[Int\]
$a\_var-is \[String\]
To get the list of properties and methods of any data type
$str = "Hello"$str | Get-Member$num = 10$num | Get-Member
PowerShell, automatically assigns a data type to a variable. However, if you explicitly want to define a data type, you are allowed to do so.
Method 1: Apply data type on variable
\[int\]$x = 100$x.GetType()
\# Once, we declared variable as Integer type, we cannot change it's type again$x = "a string value"# will throw an error
Method 2: Apply data type on value
$y = \[int\]100# We can re-use the same variable again & again with different data types$y.GetType()
$y = "a string value"$y.GetType()
Predict the type of variable – [int]$Variable = "121"
Typecasting advantage
$date\_string = "01/26/2022"
\[DateTime\]$date\_string = $date\_string$date\_string$date\_string.GetType()
Typecasting can be used for validation of data
Read, validate and write
The Read-Host
cmdlet reads a line of input from the console. You can use it to prompt a user for input. Because you can save the input as a secure string, you can use this cmdlet to prompt users for secure data, such as passwords, as well as shared data
\[string\]$name = Read-Host"What is your name"
\[int\]$age = Read-Host"What is your age"
\[DateTime\]$date = Read-Host"What is the date on which you are taking this course? Date format (dd/mm/yyyy)"
\[char\]$response = Read-Host"The trainer is doing a good job? (y/n)"$password = Read-Host"Enter your password"-AsSecureStringWrite-Host"\*\*\*\*\*\* Data Received \*\*\*\*\*\*"Write-Host"You name is: $name"Write-Host"You age is: $age"Write-Host"Date: $date"Write-Host"Response: $response"Write-Host"Response: $password"
Restrict user from entering whatever it wants
\[ValidateSet("y", "Y", "n", "N")\]$response = Read-Host"The trainer is doing a good job? (y/n)"$response
\[ValidateLength(5, 120)\]$name = \[string\](Read-Host"What is your name")
$name
\[ValidateRange(5, 100)\]$age = \[Int\](Read-Host"What is your age")
$age
To get help on the validate related commands
Get-Help about\_Functions\_Advanced\_Parameters -ShowWindow
The Write-Host
cmdlet customizes the output. You can specify the color of the text by using the foreground color paramter, and you can specify the background color by using the background color parameter.
Write-Host"Hello World! This is some sample text"Write-Host"Colorful Text"-ForegroundColor Cyan
Write-Host"More Colors"-ForegroundColor Black -BackgroundColor Red
# Better commandsWrite-Output"This is an output message"Write-Error"This is an error message"Write-Warning"This is a warning message"# These below 2 will print message only if you want them to print# If you pass the -Debug and -Verbose parameter they will print# or else won't do anythingWrite-Debug"This is debug message"-DebugWrite-Verbose"This is verbose"-Verbose
Write-Host
vs others It does not send output through the pipeline
Write-Output"Hello" | Get-MemberWrite-Host"Hello" | Get-Member# does not work# Both the below work though$var\_host = Write-Host"Hello"$var\_host$var\_output = Write-Output"Hello"$var\_output
Comparison operators let you specify conditions for comparing values and finding values that match specified patterns. To use a comparison operator, specify the values that you want to compare together with an operator that separates those values. Examples -eq
and -neq
-le
and -gt
-like
and -notlike
-contains
and -notcontains
-match
and -notmatch
\# Operator -eq2-eq2"abc"-eq"abcd""abc"-eq"ABC"# True"abc"-ceq"ABC"# False# Operator -ne"abc"-ne"hello"# Operator -lt and -gt5-lt107, 8, 9, 10-gt8# will return all the values from the left that pass this condition# -ge,-le => less than or equal and greater than or equal# Operator: -like <string\[\]> -like <wildcard-expression> (substring)# Check if "shell" is a substring of "PowerShell" "PowerShell"-like"\*shell\*""PowerShell"-clike"\*shell\*"# Operator: -notlike Does not match using the wildcard character (\*)"PowerShell"-notlike"\*Shell"
All the strings in the array that have “SSS” in them will be listed
@( # This is an array"This is a line about XYZ country",
"This is a line about ABC country",
"This is a line about SSS country",
"This is another SSS country info"
) -like"\*SSS\*"
-match
operator – This matches the string with a regular expression
It will find a match and then store the result in the $matches
variable
"Sunday"-match"sun"$matches"Sunday", "Monday", "Tuesday"-match"sun"$matches
-contains
and -notcontains
The containment operators (-contains and -notcontains) are similar to the equality operators. However, the containment operators always return Boolean value, even when the input is a collection
"Windows", "PowerShell"-contains"Shell""abc", "def"-contains"def""Windows", "PowerShell"-notcontains"Shell"
To get help on all the operators:
Get-Help about\_Comparison\_Operators -ShowWindow
Just explain comparisons in general and how we use comparison operators to make decisions.
Comparison operators let you specify conditions for comparing values and finding values that match specified patterns. To use a comparison operator, specify the values that you want to compare together with an operator that separates these values.
Example
\-eq and -neq
-le and -gt
-like and -notlike
-contains and -notcontains
-match and -notmatch
Comparison operators return true
or false
depending upong the inputs. Depending upon this result, we can proceed to make a decision within the script at runtime and do a set of tasks, if we get true and another set of tasks, if the output is false.
PowerShell syntax
If (condition) {
# Do stuff if condition is true
} else {
# Do stuff if condition is false
}
Examples
\# Example 1 If (10-eq10) {
"True"
}
else {
"False"
}
# Example 2
\[int\]$num1 = Read-Host"Enter a numberl"
\[int\]$num2 = Read-Host"Enter another number"If ($num1-eq$num2) {
"You entered $num1"
}
else {
"You entered $num1 and $num2 and they are not equal"
}
# Example 3
\[int\]$num = Read-Host"Enter a number"# -not is used for reversal of If logicif (-not ($num-le100)) {
Write-Output"Entered number $num is NOT less than 100"
}
# Example 4 - Nested If/Else loop
\[int\]$num = Read-Host"Enter a number"if ($num-gt100) {
if ($num-lt1000) {
Write-Output"Entered number $num is somewhere between 100 and 1000"
}
}
else {
Write-Output"Entered number is not in the valid range"
}
# Example 5 - If/Else with multiple conditional statements using -and
\[int\]$num = Read-Host"Enter a number"# If & only if both conditions and True, PowerShell will execute the blockif (($num-gt100) -and ($num-lt1000)) {
Write-Output"Entered number $num is somewhere between 100 and 1000"
}
else {
Write-Output"Entered number is not in the valid range"
}
# Example 6 - If/Else with multiple conditional statements using -or
\[int\]$num = Read-Host"Enter a number"# If one of the conditions is True, PowerShell will execute the blockif (($num-gt100) -or ($num-lt1000)) {
Write-Output"Entered number $num is somewhere between 100 and 1000"
}
else {
Write-Output"Entered number is not in the valid range"
}
# Example 7
\[int\]$num = Read-Host"Enter a number"If ($num-eq10) {
"You entered $num and that's equal to 10"
}
elseif ($num-eq100) {
"You entered $num and that's equal to 100"
}
elseif ($num-eq1000) {
"You entered $num and that's equal to 1000"
}
else {
"The number you entered is not 10, 100 or 1000."
}
To check multiple conditions, use a Switch statement. The Switch statement is equivalent to a series of If statements, but it is simpler. The Switch statement lists each condition and an optional action. If a condition obtains, the action is performed.
PowerShell Sytax
Switch (<test-value>) {
<condition> {<action>}
<condition> {<action>}
}
Example
\[int\]$num = Read-Host"Enter a number"Switch ($num) {
10 { "You entered $num is equal to 10" }
100 { "You entered $num is equal to 100" }
1000 { "You entered $num is equal to 1000" }
Default { "You entered $num is not 10, 100, 1000" }
}
We can use If else output and store it inside a PowerShell variable
\# Example 1$num = if ($true) { 1 } else { 2 }
$num# Example 2$day = "Sunday"$activity = if ($day-like"Sunday") { 'FUN' } else { "Work" }
$activity
A Collection is nothing but an object that groups multiple elements into a single unit.
Collections can be used to store, retrieve and manipulate data.
It is also called as a container.
Example: Array, ArrayList, HashTable etc.
A data structure to store an ordered collection of items.
To get the size of an array: $arrayname.Length
To access an item from array by index: $arrayname[index_number]
To access a range of items: $arrayname[1..5]
Array Index 0 is the index of the first item in the array, 1 is the second and (size-1) is the index of the last element in the array.
$a = 10$a.GetType()
$a = 10, 23$a = @(10, 23) # another way of creating an Array$a.GetType()
$a.Length
$names = @("John", "Jack", "James", "Jill", "Joe")
$names | Get-Member# To access array elementsWrite-Output"To get the size of an array: "$names.Length
Write-Output"To access an item from array by index: "$names\[2\]
Write-Output"To access a range of items: "$names\[1..3\]
$names\_list1 = @("John", "James", "Jack", "Joe")
$names\_list2 = @("Jill", "Jessica", "Jolene", "Jamie")
$all\_names = $names\_list1 + $names\_list2$all\_names.Length
# More array operations$all\_names.Contains("John")
$all\_names.Contains("james")
$all\_names.IndexOf("Jill")
$all\_names.IsFixedSize
$all\_names.Add("Richard Roe") # won't work because this array is of fixed size
Since arrays are of fixed size you can’t add new elements. To make a dynamic Array, use an Array List.
To frequently add elements to, remove elements from, search and modify an Array.
Class: System.Collections.ArrayList
Examples
$names = New-Object System.Collections.ArrayList
$names.Add("John")
$names.AddRange(("Jane", "Jill"))
$names$names | Get-Member
Advantages
Disadvantages
Array and ArrayList allows duplicates and is not a good choice to store unique values. Use a HashTable instead.
A hash table, also known as a dictionary or associative array, is a compact data structure that stores one or more key/value pairs.
Example, a hash table might contain a series of IP addresses and computer names, where the IP addresses are the keys and the computer names are the values, or vice versa.
Syntax
$hash = @{}
$student\_data = @{
"name" = "John Doe";
"course" = "Advanced PowerShell";
"sex" = "Male";
}
$server\_data = @{
"127.0.0.1" = "LocalHost";
"192.168.1.231" = "Telnet Server";
"192.168.1.230" = "TDP";
}
$server\_data# Different methods & properties$server\_data | Get-Member# To see the number of items$server\_data.Count
# Get all keys$server\_data.Keys
# Get all values$server\_data.Values
# Get value by key$result = $server\_data.'192.168.1.230'$result# OR$result = $server\_data\['127.0.0.1'\]
$result# To check if hash is fixed sized or not$server\_data.IsFixedSize
# Add a new pair to the hashtable$server\_data.Add("127.0.0.5", "React-Scripts server")
$server\_data# Remove a key value pair$server\_data.Remove("127.0.0.1")
$server\_data# Sorting
\[hashtable\]$hash = @{
Detail\_100 = "Value";
Detail\_01 = "Square";
Detail\_06 = "Blue";
}
# $hash.GetType()$hash.GetEnumerator() | Sort-Object-Property Key
# You can store anything inside hashtables$student\_data = @{
Person1 = @{first\_name = "John"; last\_name = "Doe" };
Person2 = @{first\_name = "Jack"; last\_name = "Smith" };
}
$student\_data$student\_data.Person2
# Get HelpGet-Help about\_Hash\_Tables -ShowWindow
The logic of this loop is to execute the while(the condition is true)(--DO--)
. Pay close attention to the style of brackets, the curly brackets or parenthesis are guiding you to write the correct code.
Syntax
$i = 1while ($i-le10) {
Write-Output"value of variable i: $i";
# $i++$i += 1# this is similar to $i = $i + 1# $i += 2
}
Write-Output"Out of the loop and proceeding with futher statements in script"
$i = 10;
do {
Write-Output"Count: $i"$i--
} while ($i-ge0)
The loop to perform a task, for set number of iterations until the condition is true.
Syntax
for (init; condition; repeat) {
# statement 1# statement 2#
}
Example
\# Example 1for ($i = 0; $i-le10; $i++) {
"Counter: $i"
}
# Example 2$arr = @("John Doe", "Jane Doe", "Jack Smith")
for ($i = 0; $i-lt$arr.Length; $i++) { # can also use $arr.CountWrite-Output$arr\[$i\]
}
\# Iterating over arrays$names = @("John Doe", "Jane Doe", "Jack Smith", "Jocelyn Daimon")
foreach ($namein$names) {
Write-Output"Hello! My name is $name"
}
# Iterating over hashtables$user\_profile = @{
Name = "John Doe";
Age = 30;
Profession = "Programmer"
}
foreach ($keyin$user\_profile.Keys) {
$message = "$key = " + $user\_profile\[$key\]
Write-Output$message
}
A function is a list of Windows PowerShell statements that has a name that you assign. When you run a function, you type the function name. The statements in the list run as if you had typed them at the command prompt.
Syntax
function Verb-Noun {
# Statement 1# Statement 2
}
# To call the function
Verb-Noun
Examples
function Say-Hello {
Write-Output"Hello World"Write-Output"How are you doing?"Write-Output"Do you have any questions?"
}
Say-Hello
Say-Hello# Function that accepts argumentsfunction Add-Numbers {
$total = $args\[0\] + $args\[1\]
Write-Output"Total: $total"
}
Add-Numbers105# Function that accepts an unlimited number of argumentsfunction Add-Numbers {
$total = 0foreach ($numin$args) {
$total += $num
}
Write-Output"Total: $total"
}
Add-Numbers105105# Function that accepts an array (always use a list of approved verbs)function Write-Hello($names) {
foreach ($namein$names) {
Write-Output"Hello! My name is $name"
}
}
$names = @("John Doe", "Jack Doe", "James McLaren")
Write-Hello$names# Function that accepts an unlimited number of argumentsfunction Write-Hello($names, $some\_message) {
foreach ($namein$names) {
Write-Output"Hello! My name is $name"
}
Write-Output$some\_message
}
$names = @("John Doe", "Jack Doe", "James McLaren")
$message = "Goodbye World!"Write-Hello$names$message
If you have a lot of paramters to pass, then it becomes difficult to remember the argument position.
Functions with named parameters
function Write-Introduction {
param (
\[string\]$Name,
\[string\]$Profession = "Programmer", # Default argument
\[string\]$Age
)
Write-Output"Hello there! My name is $Name and I am $Age years old and I work as a $Profession"
}
Write-Introduction-Name"John Doe"-Profession"Developer"-Age20Write-Introduction-Name"Jane Smith"-Profession"Full-Stack Engineer"-Age22Write-Introduction-Name"Jack Roe"-Age25
Remember in powershell, functions are called methods. Both these terms are interchangable most of the times. So when I call it a method, I’m talking about a function.
Error handling is important when creating PowerShell scripts. A script that runs correctly once may not run correctly every time.
There is always some kind of problem that can crop up when you least expect it. This is why error handling should be implemented in every important piece of PowerShell code you create.
(https://mgmt.rstforum.net/uploads/media-1701501684051.PNG)
A terminating error is an error that will halt/stop the function or an operation
Examples: syntax error, out of memory exception
A non-terminating error is an error that will allow PowerShell to continue with the execution of the script or next set of statements
Examples: Errors thrown by cmdlets
$Updated\_Geniune\_Employees\_List = Get-Content"\\\\FileServer\\HRDepartment\\Employees.txt"# Some cmdlet which returns the list of current employees# $Current\_Employees = Get-MyEmployees $Current\_Employees = @("John", "Jane", "Jack", "James", "Jill")
foreach ($empin$Current\_Employees) {
If ($Updated\_Geniune\_Employees\_List-notcontains$emp) {
Write-Output"Entry Deleted"# Delete-Employee $emp # pass employee variable as arg # to delete from the database
}
else {
Write-Output"Geniune Employee"# Update-Employee $emp "Geniune" # pass employee as arg # to update as \`Geniune\` in the database
}
}
-ErrorAction
Parameter (Alias: -EA
)It is a parameter to any cmdlet to define the action to be taken upon error.
All cmdlets accept this parameter.
Write-Error-Message"4"-ErrorAction <Continue|Ignore|Inquire|Silently Continue|Stop|Suspend>
Most cmdlets, terminate the current statement, but continue with other statements, If we want to stop the script execution right there, we can use -EA Stop
parameter to stop the execution.
$Updated\_Geniune\_Employees\_List = Get-Content \\\\FileServer\\HRDepartment\\Employees.txt -ErrorAction Stop
$ErrorActionPreference
This is a PowerShell variable which sets the preference for action to be taken on errors for all different cmdlets, instead of defining actions on individual cmdlets.
The variable can used for setting the preference for the whole script. However, if you want to set the preference for an individual command, you can do that using the ErrorAction
parameter.
$ErrorActionPreference = "Stop"$Updated\_Geniune\_Employees\_List = Get-Content \\\\FileServer\\HRDepartment\\Employees.txt -ErrorAction Stop
$Current\_Employees = @("John", "Jane", "Jack", "James", "Jill")
# $ErrorActionPreference = "SilentlyContinue"foreach ($empin$Current\_Employees) {
If ($Updated\_Geniune\_Employees\_List-notcontains$emp) {
Write-Output"Entry Deleted"# Delete-Employee $emp
}
else {
Write-Output"Geniune Employee"# Update-Employee $emp "Geniune"
}
}
-ErrorVariable
(Alias -EV
) – to store the error in a variableError variable will store the error message and you can use it later for showing it to the user or logging it inside your logfile.
It will store the error message even if error preference is set to be silently continue.
PS C:\\Users\\rst\\Documents\\Training\\PowerShell> Get-Content-path"Filename.txt"-ErrorAction SilentlyContinue -ErrorVariable"error\_var"PS C:\\Users\\rst\\Documents\\Training\\PowerShell> $error\_varGet-Content: Cannot find path 'C:\\Users\\rst\\Documents\\Training\\PowerShell\\Filename.txt' because it does not exist.
PS C:\\Users\\rst\\Documents\\Training\\PowerShell>
When an exception is thrown anywhere inside of a try
block, there’s a catch
block that’s there to catch the thrown exception and do something with it.
In PowerShell, an exception is a terminating error.
A terminating error stops a statement from running.
A Try
statement contains a try block, zero or more Catch
blocks, and zero or one Finally
block. A Try statement must have atleast one Catch block or one Finally block.
Syntax
try {
# statement\_list# You PowerShell commands that do some things
}
catch {
# statement\_list# This will execute only if an exception occured in the try block
}
finally {
# statement\_list# Finally this will execute irrespective of exceptions occurs or not
}
Example
$file\_name = "ImportantData.txt"try {
if (Test-Path$file\_name) {
Write-Output"Reading File"Get-Content$file\_name-ErrorAction Stop -ErrorVariable'err'
}
else {
throw"File not found at the shared location"
}
}
catch \[System.IO.FileNotFoundException\] {
Write-Output"File not available at $path"
}
catch \[System.IO.IOException\] {
Write-Output"Input/Output error with the file: $path"
}
catch {
$ErrorMessage = $\_.Exception.Message # $\_ represents the current object, which is nothing but the exception thrown aboveWrite-Host"Sorry, the file ($file\_name) you are looking for does not exist"-ForegroundColor Yellow
Write-Host"Err: $ErrorMessage"-ForegroundColor Red
}
finally {
Write-Host"An attempt to access the file ($file\_name) was made at $(Get-Date)"-ForegroundColor Green
}
To get more details and help on try/catch
Get-Help about\_Try\_Catch\_Finally -ShowWindow
What is a process?
In Windows NT operating systems, a Windows service is a computer program that operates in the background. It is similar in concept to a Unix daemon.
Services have no UI and mostly do not interact directly with users.
A
service
is aprocess
which runs in the background and does not interact with the desktop
Get-Process
The Get-Process
cmdlet provides a quick and easy way to retrieve information about the processes running on your computer.
Without parameters, this cmdlet gets all of the processes on the local computer. You can also specify a particular process by process name or process ID (PID) or pass a process object through the pipeline to this cmdlet.
By default, this cmdlet returns a process object that has detailed information about the process and supports methods that let you start and stop the process. You can also use the parameters of the Get-Process cmdlet to get file version information for the program that runs in the process and get the modules that the process loaded.
Get-Process
(Get-Process).GetType()
Get-Process | Sort-Object CPU
Get-Process | Sort-Object CPU | Select-Object-First10Get-Process | Sort-Object CPU -Descending | Select-Object-First10Get-Process-Name"\*pwsh\*"Get-Process-Name"\*pwsh\*" | Select-Object \*
Get-Process | Where-Object { $\_.CPU -gt100 }
Get-Process-Name"Notepad" | Stop-Process-WhatIfGet-Process-Name"Notepad" | Stop-Process# To get helpGet-HelpGet-Process-ShowWindow
Get-Service
The Get-Service
cmdlet gets objects that represent the services on a local computer or on a remote computer, including running and stopped services.
You can direct this cmdlet to get only particular services by specifying the service name or display name of the services.
By default Get-Services will return all the services on the computer.
Get-ServiceGet-Service | Sort-Object Status
Get-Service | Sort-Object Status -DescendingGet-Service-Name"\*ser\*"Get-Service-Name"\*ser\*" | Sort-Object Name
Get-Service-Name"a\*" | Where-Object { $\_.Status -eq"running" }
Get-Service-Name"a\*" | Where-Object { $\_.Status -eq"running" } | Select-Object-First3# Break up long linesGet-Service-Name"a\*"
| Where-Object { $\_.Status -eq"running" }
| Select-Object-First3Get-Service-Name"\*MongoDB\*" | Stop-Service-WhatIfGet-Service-Name MongoDB | Stop-Service# would have to \`run as administrator\`Get-Service-Name MongoDB | Start-Service# would have to \`run as administrator\`
The Task Scheduler is a tool included with Windows that allows predefined actions to be automatically executed whenever a certain set of conditions are met
Purpose
The task scheduler enables you to automatically perform routine tasks on a chosen computer. The task schedule does this by monitoring whatever criteria you choose to initiate the tasks (referred to as triggers) and then executing the tasks when the criteria is met.
Example
To open a system’s task scheduler, we can either search task schedule in windows or we can go to Run and type taskschd.msc
and search.
To read a text file into PowerShell, we can use Get-Content
cmdlet. You can use options of this command to read the desired content.
Get-Content C:\\SomeDirectory\\A\_Random\_File.txt
Test-Path
To check the existence of a file
if (Test-Path C:\\PowerShell\\test\_file\\random\_file.txt) {
Write-Output"File exists"
}
else {
Write-Output"File does not exist"
}
# Reading file after verifying it's existenceif (Test-Path .\\script1.ps1) {
Get-Content .\\script1.ps1
# Store the read value in a powershell variable$file\_content = Get-Content .\\script1.ps1
$file\_content# Only read the last three lines of a large fileGet-Content .\\script1.ps1 -Tail3# Read a specific line by it's line number
(Get-Content .\\script1.ps1)\[2\]
# To read a range of lines $file\_content = (Get-Content .\\script1.ps1)\[2..8\]
$file\_content# Searching in the file content$file\_content = Get-Content .\\script1.ps1
$file\_content | Where-Object { $\_-like"\*ERROR\*" }
$file\_content | Where-Object { $\_-like"\*INFORMATION\*" }
# Select-String for searching through the file$file\_content = Get-Content .\\script1.ps1
$file\_content | Select-String-Pattern"Error""powershell", "PowerShell", "SHELL", "Shell" | Select-String-Pattern"Shell"-CaseSensitiveSelect-String-Path .\\Notes.md -Pattern"Important"# This can be used for multiple file searches as well. You just need to # specify a wild card in the file name and it will search all the files# for that patternSelect-String-Path".\\\*.txt"-Pattern"Error"# Explore \`Select-String\` in more detail. Read the help docs.Get-HelpSelect-String-ShowWindow
}
else {
Write-Output"File does not exist"
}
With Try/Catch
try {
$file\_name = ".\\script1.ps1"if (Test-Path$file\_name) {
Write-Output"File exists"$last\_4\_lines = Get-Content-Path$file\_name-Tail4-ErrorAction Stop -ErrorVariable'err'Write-Output"As per the requirement here are the last 4 lines of your file"Write-Output$last\_4\_lines
}
else {
Write-Output"Hello User, the file you are trying to access does not exist. Please check and try again."
}
}
catch {
Write-Output"Something went wrong. Error: $err"
}
To write into a text file, we can use Out-File
cmdlet. You can use options like -Append
, -Force
, -Encoding
as per your requirement. This cmdlet will create the file if it doesn’t already exist.
Syntax
Write-Output"Some Text" | Out-File-FilePath output.txt
Examples
\# Write some text into a file (This will create the file if it does not exist already)Write-Output"$(Get-Date): This is a text" | Out-File-FilePath output.txt
# To append text at the end of an existing file (creates a file only if it does not exist)Write-Output"$(Get-Date): This is a text" | Out-File-FilePath output.txt -Append$var = "Some random variable"Write-Output"$(Get-Date): var = $var" | Out-File-FilePath output.txt -Append
CSV files are plain text files in which values tabular data is saved as comma separated values.
File extension: .csv
To import CSV file content into a PowerShell variable.
$csv\_content = Import-Csv"File-Location"
The Import-CSV
cmdlet creates table-like custom objects from the items in CSV files. Each column in the CSV file becomes a property of the custom object and the items in rows become the property values. Import-Csv
works on any CSV file, including files that are generated by the Export-Csv
cmdlet.
\# Reading CSV Files$csv\_content = Import-Csv .\\test.csv
# $csv\_content$csv\_content | Get-Member$csv\_content | Sort-Object Age
$csv\_content | Select-Object-First2$csv\_content | Where-Object { $\_.Name -like"R\*" }
$csv\_content.GetType()
# Writing the headersAdd-Content-Path users.csv -Value'Name,Age,Profession'# Array$user\_data = @(
'Rick Grimes,43,Rust Programmer';
'Rick Harrison,47,Delphi Developer';
'Harvey Specter,38,Cobol Developer';
)
# Adding content to CSV$user\_data | ForEach-Object { Add-Content-Path users.csv -Value$\_ }
# --------# Convert unsorted data file into sorted data fileImport-Csv .\\test.csv | Sort-Object Age | Export-Csv sorted\_test.csv -NoTypeInformation# -NoTypeInformation parameter omits unwanted lines of output in the starting
Extensible Markup Language (XML) is used to describe data. The XML standard is a flexible way to create information formats and electronically share structured data via the public internet, as well as via corporate networks.
XML code, a formal recommendation from the W3C, is similar to HTML. Both XML and HTML contain markup symbold to describe page or file contents.
PowerShell offers a number of different ways to read XML documents, without having to write a lot of code.
# Reading XML File
\[xml\]$xml\_content = Get-Content .\\books.xml
$xml\_content$xml\_content.GetType()
$xml\_content | Get-Member# Reading XML data$xml\_content.catalog
$xml\_content.catalog.book
$xml\_content.catalog.FirstChild
$xml\_content.GetElementsByTagName("title")
foreach ($entityin$xml\_content.GetElementsByTagName("book")) {
Write-Output$entity.author
$price = $entity.price
Write-Output$price
}
# Practical Usage# 1. Prepare application's configuration file and read it to feed values inside script# 2. Save the object state into a file. This file can be later loaded into PowerShell# and again access the same object as if we are accessing a live process (in this case).# This can be used for debugging a system problemGet-Process | Select-Object-First2 | Export-Clixml process\_output.xml
Object based PowerShell
↓ What is an object?
↓
Views & Pipelines
↓
Working with objects
↓
Formatting & Converting
↓
Class & Method
↓
Save & Recreate Objects
Real-world objects share two characteristics:
Programming Objects are conceptually similar to real-world objects:
They too consist of state and related behavior. An object stores it’s state in properties/variables/fields and exposes it’s behavior through methods.
An object is simply the programmatic representation of anything.
It is a good practice to take a look at Get-Memeber
cmdlet’s output to understand what exactly is a particular object and what it can do.
Whatever cmdlets we have seen so far which seems to be displaying plain text on the console. None of that was plain text but they were all programmable Objects.
A cmdlet is a lightweight command that is used in the Windows PowerShell environment. The Windows PowerShell runtime invokes these cmdlets within the context of automation scripts that are provided at the command line. The Windows PowerShell runtime also invokes them programatically throught Windows PowerShell APIs.
Most cmdlets are based on .NET framework classes that derive from the Cmdlet base class.
Get-ChildItem-Path C:\\Windows
Everything in PowerShell is an Object.
Proof: In front of any PowerShell entity, do a Get-Member
and observe the output. We will see both it’s properties and methods.
We can see the type of object as well.
"Something" | Get-Member
Run as administrator
Get-ServiceGet-Service-Name MongoDB | Stop-Service
(Get-Service-Name MongoDB).Start()
Piping works virtually everywhere in Windows PowerShell. Although you see text on the screen, Windows PowerShell does not pipe text between commands. Instead, it pipes objects.
A pipeline is a series of commands connected by pipeline operators (|) (ASCII 124). Each pipeline operator sends the results of the preceding command to the next command.
You can use pipelines to send the objects that are output of one command to be used as input to another command for processing. And you can send the output of that command to yet another command. The result is a very powerful command chain or pipeline that is comprised of a series of simple commands.
Command 1 | Command 2 | Command 3
Example
Get-ChildItem-Path C:\\Windows\\ | Out-File-FilePath"OutputFile.txt"
Get-ProcessGet-Process | Select \* # gives you everything, but do you need all this data?
# 1. Select-ObjectGet-Service | Select-Object-First5Get-Process | Select-Object-Last5Get-Process | Select-Object-First10-Property Name, BasePriority, CPU
Get-Process | Get-Member\# To see all the available propertiesGet-Process | Select-Object-Property \* # Get all the properties for each of the servicesGet-Process-Name"\*a\*" | Select-Object-First2# Get first 2 processes that start with have a# 2. Where-ObjectGet-Process | Where-Object { $\_.CPU -ge400 } # Get those processes who's CPU utilization is higher than 400# Can have multiple Where-Object pipesGet-Service | Where-Object { $\_.Name -like"\*a\*" }
| Where-Object { $\_.Status -eq"Stopped" }
| Select-Object-First3\# 3. Group-ObjectGet-Service | Group-Object-Property ServiceType
# 4. Sort-ObjectGet-Process | Sort-Object BasePriority | Group-Object-Property BasePriority
Get-Process | Sort-Object BasePriority | Group-Object-Property BasePriority | Select-Object-Last1Get-Process | Sort-Object BasePriority | Group-Object-Property BasePriority | Select-Object-Last1-ExpandPropertygroup\# Find top 10 processes which are consuming highest CPUGet-Process | Sort-Object CPU -Descending | Select-Object-First10# Find top 10 processes which are consuming highest Physical MemoryGet-Process | Sort-Object PM -Descending | Select-Object-First10# 5. ForEach-Object# Performs an operation against each item in a collection of input objectsGet-Process | ForEach-Object {
Write-Host"Processing: Doing something on "$\_.Name
}
1..10 | ForEach-Object {
Write-Output"Hello World"
}
Get-ChildItem-Path C:\\Users\\rst\\Documents\\Training\\PowerShell -Recurse | ForEach-Object {
Write-Output$\_.FullName
}
\# Delete all files older than 10 seconds from a directory# Do not delete subfolders$purge\_dir = "C:\\Users\\rst\\Documents\\Training\\PowerShell\\scripts\\testdir\\"$rentention\_secs = 10Get-ChildItem-File-Recurse$purge\_dir
| Where-Object { $\_.LastAccessTime -lt (Get-Date).AddSeconds(\-$rentention\_secs) }
| ForEach-Object { $\_.FullName | Remove-Item-Force-WhatIf }
# Get all the results in the form of list. Selecting all properties by wildcard(\*)Get-Service-Name"a\*" | Format-List-Property *
# Selecting few properties by nameGet-Service-Name"a\*" | Format-List-Property Name, Status, DisplayName
# Formatting TableGet-Service-Name"a\*" | Format-Table-Property Name, Status
Get-Process-Name"\*a\*" | Format-Table Name, ProductVersion, Description -Wrap# Top 10 processes which are taking highest CPUGet-Process | Sort-Object cpu -Descending | Select-Object-First10 | Format-Table ProcessName, Id, CPU, WS, PM
# ConvertTo-HtmlGet-Process | Sort-Object CPU -Descending | Select-Object-First10 | ConvertTo-Html-Property Name, CPU
Get-Service | ConvertTo-Html-Property Name, DisplayName, Status
Get-ChildItem-Path"C:\\Users\\rst"-Recurse | ConvertTo-Html-Property Name, FullName | Out-File"files\_report.html"# Add CSS to HTML$head = @"
<style>
body: {font-family: sans-serif}
table: {margin: auto; border: thin ridge grey;}
</style>
"@$body = "<h1>System's Process Information</h1><h5>Updated: on $(Get-Date)</h5>"Get-Process | Select-Object-last20 | ConvertTo-Html-Property ProcessName, \`
Handles, NPM, WS, CPU, ID, SI-Head$head-Title"Report Title"-Body$body |
Out-File"Process\_Report.html"# ConvertTo-CsvGet-Service-Name MongoDB | ConvertTo-Csv-Delimiter","# ConvertTo-JsonGet-Service-Name"\*z\*" | ConvertTo-Json# ConvertTo-XML# This cmdlet is similar to Export-Clixml except that Export-Clixml stores# the resulting XML in a file.# ConvertTo-XML returns the XML, so you can continue to process it in# Windows PowerShell.$aa = Get-Process WindowsTerminal | ConvertTo-Xml$aa.FirstChild
Get-HelpFormat-Table-ShowWindowGet-HelpConvertFrom-Json-ShowWindowGet-HelpConvertTo-Csv-ShowWindowGet-HelpConvertTo-XML-ShowWindow
A class is an extensible program-code-template for creating objects, providing initial values for state (member variables) and implementations of behavior (member functions or methods).
So inside a class we create variables and methods and then we can create Objects for the classes and these objects can be used just like the way we were using cmdlets.
class User {
\[string\]$name = "NA"
\[int32\]$age = 0
}
$user\_obj = New-Object User
$user\_obj$user\_obj.GetType()
$user\_obj | Get-Member$user\_obj.age
$user\_obj.name
$user\_obj.age = 100$user\_obj.name = "Jack Ma"$user\_obj
Example
# Example 2class MathClass {
\[int32\]$number1 = 0
\[int32\]$number2 = 0# Method 1\[int32\]Addition() {
return$this.number1 + $this.number2;
}
# Method 2\[int32\]Subtraction() {
return$this.number1 - $this.number2;
}
# Method 3\[String\]ToString() {
return"This class can be used to perform math operations on " + $this.number1 + " and " + $this.number2;
}
}
$mathclass\_obj = New-Object MathClass
# $mathclass\_obj# $mathclass\_obj | Get-Member$mathclass\_obj.number1 = 10$mathclass\_obj.number2 = 34$mathclass\_obj$mathclass\_obj.Addition()
$mathclass\_obj.Subtraction()
$mathclass\_obj.ToString()
# To get helpGet-Help about\_Classes -ShowWindow
Purpose
# Export object as XMLGet-Process | Select-Object-Last4 | Export-Clixml'process\_object.xml'# Convert the XML back to an ObjectImport-Clixml .\\process\_object.xml | Select-Object-Last2# If you want you can store it into a powershell variable$saved\_processes = Import-Clixml .\\process\_object.xml | Select-Object-Last2
$SMTPServer = "smtpout.secureserver.net"$SMTPPort = "587"$Username = "<EMAIL\_ADDRESS>"$Password = "--------------------"$to = "<EMAIL\_ADDRESS>"$cc = "hello@email.com"$subject = "Email automation using PowerShell"$body = @"
Hello User,
This is a system generated email. We just want to inform you about this.
Please do not reply to this email.
Best Regards,
Team PowerShell
Microsoft
"@$message = New-Object System.Net.Mail.MailMessage
# $message | Get-Member$message.Subject = $subject$message.Body = $body$message.To.Add($to)
$message.CC.Add($cc)
$message.From = "<EMAIL\_ADDRESS>"# $message# Create an smtp object$smtp = New-Object System.Net.Mail.SmtpClient($SMTPServer, $SMTPPort);
$smtp.EnableSsl = $true;
$smtp.Credentials = New-Object System.Net.NetworkCredential($Username, $Password);
$smtp.Send($message)
Write a PowerShell script to
#===============================================================================# System Performance Report#===============================================================================$SMTPServer = "smtpout.secureserver.net"$SMTPPort = "587"$Username = "<EMAIL\_ADDRESS>"$Password = "----------------------"$to = "<EMAIL\_ADDRESS>"$subject = "System Performance Report $(Get-Date)";
$services\_to\_monitor = @("MongoDB", "VSS", "WinRM", "TrustedInstaller", "Spooler", "msiserver");
$head = @"
<style>
body {font-family: sans-serif;}
h1,h5,th {text-align: center;}
table {margin: auto; font-family: sans-serif; border: thin ridge gray;}
th,td {border: 1px solid gray; padding: 7px 10px}
</style>
"@#===============================================================================$report = "system\_performance.html";
# High CPU$body = @"
<h3>Summary of processes taking high CPU</h3>
<p>Updated on: $(Get-Date)</p>
"@Get-Process | Sort-Object CPU -Descending | Select-Object-First10 | ConvertTo-Html-Property ProcessName, Id, CPU, WS, PM \`
-Head$head-Body$body | Out-File$reportWrite-Output"<br /><br /><br /><br />" | Out-File$report-Append# High Physical Memory$body = @"
<h3>Summary of processes taking high Physical Memory</h3>
<p>Updated on: $(Get-Date)</p>
"@Get-Process | Sort-Object PM -Descending | Select-Object-First10 | ConvertTo-Html-Property ProcessName, Id, CPU, WS, PM \`
-Body$body | Out-File$report-AppendWrite-Output"<br /><br /><br /><br />" | Out-File$report-Append# Service Monitoring$body = @"
<h3>Services Status</h3>
<p>Updated on: $(Get-Date)</p>
"@Get-Service-name$services\_to\_monitor | ConvertTo-Html-Property Name, DisplayName, Status, ServiceType, CanPauseAndContinue \`
-Body$body | Out-File$report-Append#===============================================================================$message = New-Object System.Net.Mail.MailMessage
$message.Subject = $subject$message.To.Add($to)
$message.Body = Get-Content$report$message.IsBodyHtml = $true$message.From = "<EMAIL\_ADDRESS>"$smtp = New-Object System.Net.Mail.SmtpClient($SMTPServer, $SMTPPort);
$smtp.EnableSsl = $true;
$smtp.Credentials = New-Object System.Net.NetworkCredential($Username, $Password);
$smtp.Send($message)
Advice PowerShell to execute only those scripts which are digitally signed by a trusted certificate authority.
Get-Help about\_Signing -ShowWindow
Create a codesigning certicate
$params = @{
Subject = 'CN=PowerShell Code Signing Cert'Type = 'CodeSigningCert'
CertStoreLocation = 'Cert:\\CurrentUser\\My'
}
$cert = New-SelfSignedCertificate @params
Move-Item-Path$cert.PSPath -Destination"Cert:\\CurrentUser\\Root"$CodeCert = Get-ChildItem-Path"Cert:\\CurrentUser\\Root"-CodeSigningCert# $cert | Get-Member# $cert | Select-Object \*$res = Set-AuthenticodeSignature-FilePath .\\signing\\unsigned.ps1 -Certificate$CodeCert$res.StatusMessage
Invoke-WebRequest
Gets content from a web page on the internet
Description
The Invoke-WebRequest cmdlet sends HTTP, HTTPS, FTP and FILE requests to a web page or web service. It parses the response and returns collectins of forms, links, images and other significant HTML elements. This cmdlet was introduced in Windows PowerShell 3.0.
Example
$webrequest = Invoke-WebRequest-Uri'http://books.toscrape.com/'# Getting the status code$status\_code = $webrequest.StatusCode
$status\_desc = $webrequest.StatusDescription
Write-Output"Status code returned: $status\_code"Write-Output"Status description: $status\_desc"# Getting all links embeded in a web page$webrequest.Links
$webrequest.Links | Select-Object'href'$webrequest.Links | Select-Object'href' | Out-File'urls\_found.txt'# Reading the content$webrequest.RawContent
###################################################### RUN THIS IN POWERSHELL 5 ####################################################### Reading table content from a web page $webrequest = Invoke-WebRequest-Uri"http://books.toscrape.com/catalogue/sapiens-a-brief-history-of-humankind\_996/index.html"$webrequest.ParsedHtml.GetElementsByTagName('table')\[0\].outerHTML
$webrequest = Invoke-WebRequest-Uri"https://www.w3schools.com/html/html\_forms.asp"$webrequest.Forms.fields
# Get more info$webrequest | Get-Member \*
$webrequest.ParsedHtml | Get-Member# Getting information from a web page$HTML = Invoke-WebRequest-Uri"https://en.wikipedia.org/wiki/PowerShell"$tables = @($HTML.ParsedHtml.GetElementsByTagName("table"))
$tables\[0\].rows\[8\].GetElementsByTagName('div')\[0\].innerText.split('/')\[0\]
############################################### Download a file$url = "http://books.toscrape.com/media/cache/ce/5f/ce5f052c65cc963cf4422be096e915c9.jpg"## Method 1$web\_client = New-Object System.Net.WebClient
$web\_client.DownloadFile($url, "C:\\Users\\rst\\Documents\\Training\\PowerShell\\scripts\\testimage.jpg")
## Method 2Invoke-WebRequest$url-OutFile"C:\\Users\\rst\\Documents\\Training\\PowerShell\\scripts\\testimage2.jpg"# Download all images from a website$BASE\_NAME = "http://books.toscrape.com/"$my\_website = Invoke-WebRequest-Uri"http://books.toscrape.com/index.html"-UseBasicParsing$my\_website.Images.src.ForEach({
$filename = $\_ | Split-Path-LeafWrite-Host"Download image file $filename"Invoke-WebRequest-Uri"$BASE\_NAME$\_"-OutFile"C:\\Users\\rst\\Documents\\Training\\PowerShell\\scripts\\images\\$filename"Write-Host"Image download complete"
})
Invoke-Expression
and Executing Web content as scriptThe Invoke-Expression
cmdlet evaluates or runs a specified string as a command and returns the results of the expression or command. Without it, a string submitted at the command line would be returned (echoes) unchanged.
$Command = 'Get-Process | Where-Object {$\_.CPU -gt 500}'Invoke-Expression$Command# Example 2$script = @'
Write-Host "===================================================="
$Celsius = \[double\](Read-Host "Enter temperature in Fahrenheit")
# Caluclating temperature in $Kelvin
$Kelvin = $Celsius + 273.15
Write-Output "$Celsius degree Celsius is equivalent to $Kelvin K"
Write-Host "FYI: Top 5 processes using maximum PM of your computer:" -BackgroundColor DarkBlue -ForegroundColor red
Get-Process | Sort-Object PM -Descending | Select-Object -First 5
'@Invoke-Expression$script
# ==============================================================================# CREATE AND FILL THE DATABASE# ==============================================================================Import-Module PSSQLite -Verbose# Create a database$Database = "system\_info.db"$Conn = New-SQLiteConnection-DataSource$DatabaseInvoke-SqliteQuery-Query"DROP TABLE IF EXISTS DOMAIN\_SYSTEM\_INFORMATION"-SQLiteConnection$Conn# Create a database and a table$Query = "CREATE TABLE DOMAIN\_SYSTEM\_INFORMATION (id NUMBER PRIMARY KEY, ip\_address VARCHAR(20), server\_name VARCHAR(100), os\_version VARCHAR(100), status VARCHAR(100))"Invoke-SqliteQuery-Query$Query-SQLiteConnection$Conn# # View table info# Invoke-SqliteQuery -SQLiteConnection $Conn -Query "PRAGMA table\_info(DOMAIN\_SYSTEM\_INFORMATION)" | Out-GridView# Insert dataInvoke-SqliteQuery-SQLiteConnection$Conn-Query"INSERT INTO DOMAIN\_SYSTEM\_INFORMATION (id, ip\_address, server\_name, os\_version, status) VALUES (1,'123.123.123.123','SEVER\_NAME1','Windows Server 2008','Good')"Invoke-SqliteQuery-SQLiteConnection$Conn-Query"INSERT INTO DOMAIN\_SYSTEM\_INFORMATION (id, ip\_address, server\_name, os\_version, status) VALUES (2,'321.321.123.123','SEVER\_NAME2','Windows Server 2008','Ping Failure-Unable to connect')"Invoke-SqliteQuery-SQLiteConnection$Conn-Query"INSERT INTO DOMAIN\_SYSTEM\_INFORMATION (id, ip\_address, server\_name, os\_version, status) VALUES (3,'123.123.123.123','SEVER\_NAME3','Windows Server 2012','CPU utiliztion is high')"Invoke-SqliteQuery-SQLiteConnection$Conn-Query"INSERT INTO DOMAIN\_SYSTEM\_INFORMATION (id, ip\_address, server\_name, os\_version, status) VALUES (4,'123.123.123.100','SEVER\_NAME4','Windows Server 2008','Physical Memory Utilization is high')"Invoke-SqliteQuery-SQLiteConnection$Conn-Query"INSERT INTO DOMAIN\_SYSTEM\_INFORMATION (id, ip\_address, server\_name, os\_version, status) VALUES (5,'321.321.123.101','SEVER\_NAME5','Windows Server 2008','Good')"Invoke-SqliteQuery-SQLiteConnection$Conn-Query"INSERT INTO DOMAIN\_SYSTEM\_INFORMATION (id, ip\_address, server\_name, os\_version, status) VALUES (6,'123.123.123.102','SEVER\_NAME6','Windows Server 2012','Shutdown')"Invoke-SqliteQuery-SQLiteConnection$Conn-Query"INSERT INTO DOMAIN\_SYSTEM\_INFORMATION (id, ip\_address, server\_name, os\_version, status) VALUES (7,'123.123.123.103','SEVER7','Windows Server 2008','Accidently Rebooted')"Invoke-SqliteQuery-SQLiteConnection$Conn-Query"INSERT INTO DOMAIN\_SYSTEM\_INFORMATION (id, ip\_address, server\_name, os\_version, status) VALUES (8,'321.321.123.110','SEVER\_NAME8','Windows Server 2008','Netowrk Latency Observed')"# # View thje data# Invoke-SqliteQuery -SQLiteConnection $Conn -Query "SELECT \* FROM DOMAIN\_SYSTEM\_INFORMATION LIMIT 10"# ==============================================================================# VARIABLE SETUP# ==============================================================================$BASE\_DIR = (Resolve-Path .\\).Path
$LOG\_FILE = $BASE\_DIR + "\\daily\_server\_status\_report.log"# CSS Stylings$Head = @"
<style>
h1, h5, th { text-align: center; }
table { margin: auto; font-family: Segoe UI; box-shadow: 10px 10px 5px #888; border: thin ridge grey; }
th { background: #0046c3; color: #fff; max-width: 400px; padding: 5px 10px; }
td { font-size: 11px; padding: 5px 20px; color: #000; }
tr { background: #b8d1f3; }
tr:nth-child(even) { background: #dae5f4; }
tr:nth-child(odd) { background: #b8d1f3; }
</style>
"@$Report = $BASE\_DIR + "\\daily\_status.html"Write-Output"$(Get-Date) :INFO Staring the script Execution " | Out-File$LOG\_FILE-Append-Force# ==============================================================================# PREPARING REPORT# ==============================================================================try {
$Query = "SELECT \* FROM DOMAIN\_SYSTEM\_INFORMATION"$DataTable = Invoke-SqliteQuery-SQLiteConnection$Conn-Query$QueryWrite-Output"$(Get-Date) :Executing queryString: $Query" | Out-File$LOG\_FILE-Append-Force$Body = "<h3>Daily Summary</h3>\`n<h3>Updated: on $(Get-Date)</h3>"$DataTable | ConvertTo-Html-Property ip\_address, server\_name, os\_version, status -Head$head-Body$Body | Out-File$report
}
catch {
$ErrorMessage = $\_.Exception.Message
Write-Output"$(Get-Date) :ERROR Something went Wrong ErrorMessage : $ErrorMessage " | Out-File$LOG\_FILE-Append-Force
}
Write-Output"$(Get-Date) :INFO Report Preparation Execution Over" | Out-File$LOG\_FILE-Append-Force# ==============================================================================# SENDING EMAIL# ==============================================================================try {
$SMTPServer = "smtpout.secureserver.net"$SMTPPort = "587"$Username = "<EMAIL\_ADDRESS>"$Password = "<PASSWORD>"$To = "<EMAIL\_ADDRESS>"$Subject = "Daily Status Report: $(Get-Date)";
$Message = New-Object System.Net.Mail.MailMessage
$Message.Subject = $Subject$Message.To.Add($To)
$Message.Body = Get-Content$Report$Message.IsBodyHtml = $true$Message.From = "<EMAIL\_ADDRESS>"$smtp = New-Object System.Net.Mail.SmtpClient($SMTPServer, $SMTPPort);
$smtp.EnableSsl = $true;
$smtp.Credentials = New-Object System.Net.NetworkCredential($Username, $Password);
$smtp.Send($Message)
Write-Output"$(Get-Date) :INFO Email Sent" | Out-File$LOG\_FILE-Append-Force;
}
catch {
$ErrorMessage = $\_.Exception.Message
Write-Output"$(Get-Date) :ERROR Something went Wrong. ErrorMessage : $ErrorMessage " | Out-File$LOG\_FILE-Append-Force;
}
finally {
Write-Output"$(Get-Date) : Script Execution Completed " | Out-File$LOG\_FILE-Append-Force;
}
WMI (Windows Management Instrumentation) is Microsoft’s implementation of the Web-Based Enterprise Management (WBEM) and Common Information Model (CIM) standards from the Distributed Management Task Force (DMTF).
WMI allows scripting languages (such as VBScript or Windows PowerShell) to manage Microsoft Windows personal computers and servers, both locally and remotely. WMI comes preinstalled in Windows 2000 and in newer Microosft OSes.
Common Information Model (CIM), a computer industry standard for defining device and application characteristics so that system administrators and management programs can control devices and applications from multiple manufacturers or sources in the same way.
WMI provides users with information about the status of local or remote computer systems.
It also supports such actions as the configuration of security settingsm settings and changing system properties, settings and changing permissions for authorized users and user groups, assigning and changing drive labels, scheduling processes to run at specific times, backing up the object repository, and enabling or disabling error logging.
Get-WmiObject
There are several WMI namespaces created which are aligned to each major product, and depending on the namespace, hundred of classes can be created under each namespace.
Example:
root\directory\Idap
root\Microsoft\ComputerManagement12\instance_name
root\CCM\Schedules
root\cimv2
root\CCM\Events
\
# Get a list of all the namespacesGet-WmiObject-Namespace"root"-Class"\_\_Namespace" | Select Name
# To get all the classes from a namespaceGet-WmiObject-Namespace'root\\cimv2'-List
(Get-WmiObject-Namespace'root\\cimv2'\-List).count
Get-WmiObject-Namespace'root\\cimv2'\-List | Out-GridView\# Fetching all properties by class nameGet-WmiObject-Class'Win32\_Service'# WMI on remote machinesGet-WmiObject-Class'Win32\_Service'-ComputerName'localhost'# Using WQL# Fetching results by a QueryGet-WmiObject-Query"select \* from Win32\_Service"# Fetching results by a Query (remote)Get-WmiObject-ComputerName'localhost'-Query"select \* from Win32\_Service"
Windows Management Instrumentation Query Language (WQL) is Microsoft’s implementation of the CIM Query Language (CQL), a query language for the Common Information Model (CIM) standard from the Distributed Management Task Force (DMTF).
It is a subset of ANSI standard SQL with minor semantic changes
Examples
# Get disk drivesGet-WmiObject-Class'Win32\_LogicalDisk'-ComputerName'localhost'# Get different drives using WMIGet-WmiObject-Class'Win32\_LogicalDisk'-ComputerName'localhost'-Filter'DriveType=3'# Doing the same as above but using WQL QueryGet-WmiObject-Query"select \* from Win32\_LogicalDisk"-ComputerName'localhost'Get-WmiObject-Query"select \* from Win32\_LogicalDisk where DriveType=3"-ComputerName'localhost'
# To get the information about operating systemGet-WmiObject-Query"select \* from Win32\_OperatingSystem"-ComputerName'localhost' | Out-GridView# To get the information about different processes running on a remote machineGet-WmiObject-Query"select \* from Win32\_Process"-ComputerName'localhost' | Out-GridView# To get information about computer systemGet-WmiObject-Query"select \* from Win32\_ComputerSystem"-ComputerName'localhost' | Out-GridView# To get information about running servicesGet-WmiObject-Query"select \* from Win32\_Service where State = 'Running'"-ComputerName'localhost' | Out-GridView
Requirement
Write a script to gather the disk space of multiple disk drives of multiple servers. Output should be sent as an email and disk should be categorized as:
Script can be scheduled to send output in multiple ways:
We should use a configuration file for feeding our preferences to the script
<DAILY\_REPORT><MONITOR\_SERVERS><SERVER>localhost</SERVER><SERVER>localhost</SERVER><SERVER>localhost</SERVER><SERVER>localhost</SERVER><!-- Any Extra row if required--></MONITOR\_SERVERS><MONITOR\_THRESHOLD ><!-- Since idea is to create an alarm if disk space is higher than a threshold value, --><!-- Threshold should be around 80-90 ideally, however it should be fine tuned as per your need --><!-- You can enhance your script logic and set different threshold for different type of drives --><DISKSPACE\_ERROR>90</DISKSPACE\_ERROR><DISKSPACE\_WARNING>80</DISKSPACE\_WARNING>
</MONITOR\_THRESHOLD >
<EMAIL><FROM><EMAIL\_ADDRESS></FROM><TO><EMAIL\_ADDRESS></TO><SUBJECT>Disk Space Alert</SUBJECT><SMTP>smtpout.secureserver.net</SMTP><SMTP\_USERNAME><EMAIL\_ADDRESS></SMTP\_USERNAME><SMTP\_PASSWORD><PASSWORD></SMTP\_PASSWORD></EMAIL></DAILY\_REPORT>
# ==============================================================================# SETTING UP VARIABLES# ==============================================================================$BASE\_DIR = (Resolve-Path .\\).Path
$LOG\_FILE = $BASE\_DIR + "\\daily\_diskspace\_status.log"# CSS Stylings$Head = @"
<style>
h1, h5, th { text-align: center; }
table { margin: auto; font-family: Segoe UI; box-shadow: 10px 10px 5px #888; border: thin ridge grey; }
th { background: #0046c3; color: #fff; max-width: 400px; padding: 5px 10px; }
td { font-size: 11px; padding: 5px 20px; color: #000; }
tr { background: #b8d1f3; }
tr:nth-child(even) { background: #dae5f4; }
tr:nth-child(odd) { background: #b8d1f3; }
</style>
"@$report = $BASE\_DIR + "\\daily\_diskSpace\_status.html"$xml\_config = $BASE\_DIR + "\\configuration.xml"
\[xml\]$xml\_content = Get-Content$xml\_configWrite-Output"$(Get-Date) :INFO Staring the script Execution" | Out-File$LOG\_FILE-Append-Force;
$diskspace\_error\_threshold = \[int32\] $xml\_content.DAILY\_REPORT.MONITOR\_THRESHOLD.DISKSPACE\_ERROR
$diskspace\_warning\_threshold = \[int32\] $xml\_content.DAILY\_REPORT.MONITOR\_THRESHOLD.DISKSPACE\_WARNING
# ==============================================================================# PREPARING REPORT# ==============================================================================try {
foreach ($entityin$xml\_content.DAILY\_REPORT.MONITOR\_SERVERS ) {
$server = $entity.SERVER
$body = "<h3>Daily Summary</h3>\`n<h3>Updated: on $(Get-Date)</h3>"Get-WmiObject-Query"select \* from Win32\_LogicalDisk where drivetype=3"-ComputerName$server |
Select-Object SystemName, DeviceId, @{Name = "Size"; Expression = { \[math\]::Round($\_.Size / 1GB, 2) } }\`
, @{Name = "FreeSpace"; Expression = { \[math\]::Round($\_.FreeSpace / 1GB, 2) } } \`
, @{Name = "Occupied"; Expression = { \[math\]::Round(100 - ( \[double\]$\_.FreeSpace / \[double\]$\_.Size ) \* 100) } } |
Export-Csv disk\_space.csv -NoTypeInformation
}
$csv\_content = Import-CSV'disk\_space.csv'$body = "<h3>Servers in Error Status</h3>\`n<h3>Updated: on $(Get-Date)</h3>"$csv\_content | Where-Object { $\_.Occupied -ge$diskspace\_error\_threshold } | ConvertTo-Html-property SystemName, DeviceId, Size, FreeSpace, Occupied \`
-Head$head-Body$body | Out-File$report$body = "<h3>Servers in Warning Status</h3>\`n<h3>Updated: on $(Get-Date)</h3>"$csv\_content | Where-Object { $\_.Occupied -lt$diskspace\_error\_threshold-and$\_.Occupied -gt$diskspace\_warning\_threshold } |
ConvertTo-Html-property SystemName, DeviceId, Size, FreeSpace, Occupied \`
-Body$body | Out-File$report-Append$body = "<h3>Servers in Good Status</h3>\`n<h3>Updated: on $(Get-Date)</h3>"$csv\_content | Where-Object { $\_.Occupied -lt$diskspace\_warning\_threshold } | ConvertTo-Html-property SystemName, DeviceId, Size, FreeSpace, Occupied \`
-Body$body | Out-File$report-Append
}
catch {
$ErrorMessage = $\_.Exception.Message
Write-Output"$(Get-Date) :ERROR Something went Wrong ErrorMessage : $ErrorMessage " | Out-File$LOG\_FILE-Append-Force;
}
Write-Output"$(Get-Date) :INFO Report Preparation Execution Over" | Out-File$LOG\_FILE-Append-Force;
# ==============================================================================# SENDING EMAIL# ==============================================================================try {
$SMTPServer = "smtpout.secureserver.net"$SMTPPort = "587"$Username = "<EMAIL\_ADDRESS>"$Password = "<PASSWORD>"$To = "<EMAIL\_ADDRESS>"$Subject = "Daily Status Report: $(Get-Date)";
$Message = New-Object System.Net.Mail.MailMessage
$Message.Subject = $Subject$Message.To.Add($To)
$Message.Body = Get-Content$report$Message.IsBodyHtml = $true$Message.From = "<EMAIL\_ADDRESS>"$smtp = New-Object System.Net.Mail.SmtpClient($SMTPServer, $SMTPPort);
$smtp.EnableSsl = $true;
$smtp.Credentials = New-Object System.Net.NetworkCredential($Username, $Password);
$smtp.Send($Message)
Write-Output"$(Get-Date) :INFO Email Sent" | Out-File$LOG\_FILE-Append-Force;
}
catch {
$ErrorMessage = $\_.Exception.Message
Write-Output"$(Get-Date) :ERROR Something went Wrong. ErrorMessage : $ErrorMessage " | Out-File$LOG\_FILE-Append-Force;
}
finally {
Write-Output"$(Get-Date) : Script Execution Completed " | Out-File$LOG\_FILE-Append-Force;
}
Event Viewer is a component of Microsoft’s Windows NT line of operating systems that lets administrators and users view the event logs on a local or remote machine.
Event Viewer allows you to monitor events in your system. It maintains logs about programs, security, and system events on your computer. You can use Event Viewer to view and manage the event logs, gather information about hardware and software problems, and monitor security events.
To access Device Manager, on the Start menu, click Programs, point to Administration Tools, and then click on Event Viewer.
We can use the Event Viewer to view and manage the system, application, and security event logs.
The System log records events logged by the Windows system components.
For example, the failure of a driver or other system components to load during startup is recorded in the System log.
The Application log records events logged by programs.
For example, a database program might record a file error in the Application log. Program developers decide which events to monitor.
THe Security log records security events, such as valid and invalid logon attempts, and events related to resource use, such as creating, opening, or deleting files or other objects. The Security log helps track changes to the security system and identify any possible breaches to security. For example, attempts to log on the system might be recorded in the Security log, if logon and logoff auditing are enabled.
You can view the Security log only if you are an administrator for a computer.
Get-EventLogGet-HelpGet-EventLog-Online# List different types of logs availableGet-EventLog-List# Get event logsGet-EventLog-LogName"Application"Get-EventLog-Newest5-LogName"Application"# Store the event log in a PowerShell Array$Events = Get-EventLog-LogName Application -Newest10$Events# and then use the array as per your need$Events | Group-Object-Property source -NoElement | Sort-Object-Property Count -Descending# Get only the \`error\` type messages from a particular type of logGet-EventLog-LogName"System"-EntryType Error -Newest10# Read specific events by filteringGet-EventLog-LogName"Application"-Source"Desktop Window Manager" | Where-Object { $\_.eventID -eq9027 }
# Get all messages between a selected time range$endTime = Get-Date# present time# $endTime$startTime = $endTime.AddHours(-1) # last 1 hour (AddDays, AddMinutes)# $endTime# Get-EventLog -LogName "Application" -EntryType Information -After $startTime -before $endTime# Save the output to HTML/CSS and send in emailGet-EventLog-Log"Application"-EntryType Information -After$startTime-before$endTime | ConvertTo-Html Index, Source, Time, Message | Out-File"Out.html"# Read event logs of remote computersGet-EventLog-Newest2-LogName"Windows PowerShell"-ComputerName"localhost", "remoteMachine1", "remoteMachine2"Get-EventLog-Newest2-LogName"Windows PowerShell"-ComputerName'localhost', 'localhost', 'localhost'# DOESN'T WORK# Reading the event logs using WMIGet-WmiObject-class Win32\_NTLogEvent
$Log\_message = Get-WmiObject-class Win32\_NTLogEvent -Filter"(logfile='Application') AND (type='error')" | Select-Object-First4$Log\_message | Format-Table EventCode, EventType, Message -AutoSize
# Register source to an existing event log and writeNew-EventLog-LogName'Application'-Source'My Script'# RUN THE BELOW IN POWERSHELL ADMIN MODENew-EventLog-LogName'Application'-Source'My Script'# execute this firstWrite-EventLog-LogName'Application'-Source'My Script'-EntryType Error -EventId1-Message'This is a test message'
Advanced functions allow you to write functions that can perform operations that are similar to the operations you can perform with cmdlets.
Advanced functions are helpful when you want to quickly write a function without having to write a compiled cmdlet using a Microsoft .NET Framework language.
These functions are also helpful when you want to restrict the functionality of a compiled cmdlet or when you want to write a function that is similar to a compiled cmdlet.
# Add-To Functionfunction Add-Numbers {
param($num1, $num2)
Write-Host ($num1 + $num2)
}
## Calling the function with argumentsAdd-Numbers1219Add-Numbers"Hello""World"# Typecasting to avoid concatenation and bringing unpredictibility# Add-To Functionfunction Add-Numbers {
param(\[int\]$num1, \[int\]$num2)
Write-Host ($num1 + $num2)
}
## Calling the function with argumentsAdd-Numbers1219Add-Numbers"Hello""World"
CmdletBinding()
The cmdletbinding()
attribute is an attribute of functions that makes them operate like compiled cmdlets that are written in C#, and it provides access to features of cmdlets.
Windows PowerShell binds the parameters of functions that have the CmdletBinding attribute in the same way that it binds the parameters of compiled cmdlets.
function Add-Numbers {
\[cmdletbinding()\] # converts this function to an advanced functionparam(\[int\]$num1, \[int\]$num2)
Write-Verbose"Performing some really complex calculation"Write-Host ($num1 + $num2)
Write-Debug"Calculation completed"
}
## Calling the function with argumentsAdd-Numbers1219-VerboseAdd-Numbers1121-DebugAdd-Numbers562-23-ErrorAction SilentlyContinue
Write-Verbose
and Write-Debug
in your script or function and have their output controlled by -Verbose
and -Debug
parameters of that script or function-EV
and -EA
-whatif
and -confirm
added to your script or functionSupportsShouldProcess
The SupportsShouldProcess
argument adds Confirm
and WhatIf
parameters to the function.
The Confirm
parameter prompts the user before it runs the command on each object in the pipeline. The WhatIf
parameter lists the changes that the command would make, instead of running the command.
The SupportsShouldProcess
tells the shell that your function supports both -Confirm
and -WhatIf
. The way you actually implement that support is to write conditional code around whatever dangerous stuff your cmdlet is planning to do.
ShouldContinue
This method is called to request a second confirmation message. It should be called when the ShouldProcess
method returns $true
.
function Add-Numbers {
\[cmdletbinding(SupportsShouldProcess = $true)\]param(\[int\]$num1, \[int\]$num2)
Write-Verbose"Performing some really complex calculation"Write-Host ($num1 + $num2)
Write-Debug"Calculation completed"
}
function Add-Numbers {
\[cmdletbinding()\]param(
\[parameter(Mandatory = $true)\]
\[int\]$num1,
\[parameter(Mandatory = $true)\]
\[int\]$num2
)
Write-Verbose"Performing some really complex calculation"Write-Host ($num1 + $num2)
Write-Debug"Calculation completed"
}
Add-Numbers10
function Add-Numbers {
\[cmdletbinding()\]param(
\[parameter(Mandatory = $true, HelpMessage = "Please pass the first number to add")\]
\[int\]$num1,
\[parameter(Mandatory = $true, HelpMessage = "Please pass the second number to add")\]
\[int\]$num2
)
Write-Verbose"Performing some really complex calculation"Write-Host ($num1 + $num2)
Write-Debug"Calculation completed"
}
Add-Numbers
function Delete-Something {
\[CmdletBinding(SupportsShouldProcess = $true, ConfirmImpact = "high")\]Param ($param1)
PROCESS {
if ($PSCmdlet.ShouldProcess($param1)) {
Write-Verbose"deleting the file"Remove-Item testfile.txt
}
}
}
Delete-Something"AdOrgUnit"
Delete-Something"AdOrgUnit"-WhatIf
This block is used to provide optional one-time preprocessing for the function. The Windows PowerShell runtime uses the code in this block one time for each instance of the function in the pipeline.
This block is used to provide record-by-record processing for the function. This block might be used any number of times, or not at all, depending on the input to the function.
For example, if the function is the first command in the pipeline, the Process block will be used one time. If the function is not the first command in the pipeline, the Process block is used one time for every input that the function receives from the pipeline. If there is no pipeline input, the Process block is not used.
This block is used to provide optional one-time post-processing for the function.
function Hello-World {
\[CmdletBinding()\]param (
\[Parameter(Mandatory = $false, ValueFromPipeline = $true)\] # this function can accept values from pipeline$Param1
)
begin {
"This is the Begin block $Param1"
}
process {
"This is the Process block $Param1"
}
end {
"This is the End block $Param1"
}
}
# Hello-World1..10 | Hello-World# ==============================================================================# Example: Write an advanced function for getting the sum of whatever numbers# are passed to it via a pipefunction Add-All {
\[CmdletBinding()\]param (
\[Parameter(Mandatory = $false, ValueFromPipeline = $true)\]
\[int32\]$number
)
begin {
Write-Host"Received the input to add the numbers"$total = 0
}
process {
Write-Host"Adding $number to $total"$total = $total + $number
}
end {
Write-Host"Total is: $total"
}
}
1..20 | Add-All@(10, 100, 200) | Add-All
Write a reusable advanced function such that it can be used for getting the status of one or more URLs.
Function should be written in such a way that debugging remains easy and function could be used for monitoring of multiple websites.
function Get-URLStatus {
\[CmdletBinding()\]param (
# Parameter help description
\[Parameter(Mandatory = $true, ValueFromPipelineByPropertyName = $true, ValueFromPipeline = $true, Position = 0)\]
$URI,
\[switch\] $errorlog, # if passed then it is true, or else it will be false
\[String\] $logfile = "C:\\Users\\rst\\Documents\\Training\\PowerShell\\scripts\\test.log"
)
begin {
if ($errorlog) {
Write-Output"Checking the URL status" | Out-File$logfile-Append
}
}
process {
try {
$webrequest = Invoke-WebRequest-Uri$URI# Getting the status code# 200 means no HTTP request error$status\_code = $webrequest.StatusCode
if ( $status\_code-eq200) {
if ($errorlog) { Write-Output"$URI :: $status\_code :: GOOD" | Out-File$logfile-Append-Force; }
Write-Host"$URI :: $status\_code :: GOOD"-BackgroundColor Green -ForegroundColor DarkBlue
}
else {
if ($errorlog) { Write-Output"$URI :: $status\_code :: GOOD" | Out-File$logfile-Append-Force; }
Write-Host"$URI :: $status\_code :: BAD"-BackgroundColor red -ForegroundColor Yellow
}
}
catch {
$ErrorMessage = $\_.Exception.Message
if ($errorlog) {
Write-Output"Something went wrong while checking status of URL : $URI" | out-file$logfile-Append-Force;
Write-Output"#ERROR1a# ErrorMessage : $ErrorMessage" | out-file$logfile-Append-Force;
}
}
}
end {
if ($errorlog) { Write-Output"Done with invoking web request for all URLs" | Out-File$logfile-Append }
}
}
Get-URLStatus-URI'https://u5b.f44.myftpupload.com'-errorlogGet-URLStatus-URI'https://u5b.f44.myftpupload.com'-errorlog-logfile"new\_name.log"# passing variable via a pipeline$arr\_URIs = @("https://www.facebook.com/", "https://www.google.co.in", "http://mail.google.com");
$arr\_URIs | Get-URLStatus-Verbose-errorlog