├── .vscode
└── launch.json
├── LICENSE
├── README.md
├── best-practices.md
├── ch02
└── hello-world.ps1
├── ch04
└── Initialize-PacktPs6CoreLinuxLab.ps1
├── ch05
├── 6.2-dotnetcore-obj.ps1
└── 6.6-CustomTypes.ps1xml
├── ch06
├── 03-input-file-expanding.txt
├── 03-input-file.txt
├── 05-Get-TravelArticles.ps1
├── 05-sitelist.csv
├── 06-puregfm.md
├── 06-rawcontent.txt
├── 07-input.csv
├── 07-split-input.ps1
├── 08-details.txt
└── 08-mailto.txt
├── ch07
├── 02.1-Get-WeekDay-if-else.ps1
├── 02.2-Get-Weekday-switch-case.ps1
├── 03-Wait-BeforeDressCode.ps1
├── 04-Write-Greetings.ps1
├── 05-Write-GuestSeatDetails.csv
├── 05-Write-GuestSeatDetails.ps1
├── 06-Write-GuestSeatDetails.ps1
├── 07.1-Write-GuestSeatDetails.ps1
├── 07.2-Find-MothersDay.ps1
├── 08-Remove-EmptyDirectories.ps1
├── 08-input-file.txt
└── 09-Remove-EmptyDirectories.ps1
├── ch08
├── 01-Clear-LogFiles.ps1
├── 01-Set-LastWriteTime.ps1
├── 02-Clear-LogFiles.ps1
├── 05-ConvertTo-Rgb.ps1
└── 06-ConvertTo-OtherBases.ps1
├── ch09
├── 01-New-MultiDimensionalArray.ps1
├── 02-Convert-Name.ps1
├── 02-names.txt
├── 03-Convert-SortedNames.ps1
├── 04-Find-Name.ps1
├── 05-Combine-Arrays.ps1
├── 05-list-one.txt
├── 05-list-two.txt
├── 06-Search-ByLastname01.ps1
├── 06-Search-ByLastname02.ps1
├── 07-Clear-Paths01.ps1
├── 07-Clear-Paths02.ps1
├── 08-Compare-ServerName.ps1
├── 08-server-names-01.txt
├── 08-server-names-02.txt
├── 09-New-MemoryList.ps1
└── 10-New-ProcessReport.ps1
├── ch10
├── 01-Get-FileDetails.ps1
├── 01-random-text.txt
├── 02-Write-ContentOne.ps1
├── 02-Write-ContentTwo.ps1
├── 03-Modify-FileContent.ps1
├── 04-Search-FileForPattern.ps1
├── 05-Get-InvocationInformation.ps1
├── 06-New-FilesAndDirectories.ps1
├── 07-Get-FilteredFiles.ps1
├── 08-Read-MdmLog.ps1
└── 08-mdm-reinstall-log.log
├── ch11
├── 04-Start-Count.ps1
├── 05-Start-Count.ps1
├── 06-Start-Count.ps1
└── 07-Start-Count.ps1
├── ch12
├── 01-Start-Count.ps1
├── 01-Start-CountFlexible.ps1
├── 02-Start-Count.ps1
├── 03-New-PersonalMessage.ps1
├── 04-Start-Count.ps1
├── 05-Start-Count.ps1
├── 06-New-File.ps1
├── 07-New-File.ps1
├── 08-Start-Count.ps1
├── 09-New-File.ps1
├── 10-New-File.ps1
├── 11-New-File.psm1
└── 12-New-File.psm1
├── ch13
├── 01-New-File.ps1
├── 02-New-File.ps1
├── 03-Set-Name.ps1
├── 04-New-File.ps1
├── 05-Set-Name.ps1
├── 06-Find-Item.ps1
├── 07-Find-Item.ps1
├── 08-New-LogFile.ps1
└── 09-New-LogFile.ps1
├── ch14
├── 01-PoSH-Remote-Query.ps1
├── 02-PoSH-Remote-Query-HTML.ps1
├── 03-PoSH-Remote-Query-HTML-Mail.ps1
└── Input.CSV
├── ch15
└── SampleAzureRmVM.ps1
├── ch16
├── Install-SqlServer.ps1
├── New-DataFormatExample.ps1
├── New-GetProcessRepo.ps1
├── New-MultiServerTsql.ps1
├── New-TsqlQuery.ps1
└── program.cs
├── ch17
├── PoSH-Find-DockerTags.ps1
└── PoSH-Setup-Docker.ps1
├── cheatsheets
├── chapter-01.md
├── chapter-02.md
├── chapter-03.md
├── chapter-04.md
├── chapter-05.md
├── chapter-06.md
├── chapter-07.md
├── chapter-08.md
├── chapter-09.md
├── chapter-10.md
├── chapter-11.md
├── chapter-12.md
└── chapter-13.md
└── miscellaneous
└── Microsoft.VSCode_profile.ps1
/.vscode/launch.json:
--------------------------------------------------------------------------------
1 | {
2 | // Use IntelliSense to learn about possible attributes.
3 | // Hover to view descriptions of existing attributes.
4 | // For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387
5 | "version": "0.2.0",
6 | "configurations": [
7 | {
8 | "type": "PowerShell",
9 | "request": "launch",
10 | "name": "PowerShell Launch Current File",
11 | "script": "${file}",
12 | "args": [],
13 | "cwd": "${file}"
14 | },
15 | {
16 | "type": "PowerShell",
17 | "request": "launch",
18 | "name": "PowerShell Launch Current File in Temporary Console",
19 | "script": "${file}",
20 | "args": [],
21 | "cwd": "${file}",
22 | "createTemporaryIntegratedConsole": true
23 | },
24 | {
25 | "type": "PowerShell",
26 | "request": "launch",
27 | "name": "PowerShell Launch Current File w/Args Prompt",
28 | "script": "${file}",
29 | "args": [
30 | "${command:SpecifyScriptArgs}"
31 | ],
32 | "cwd": "${file}"
33 | },
34 | {
35 | "type": "PowerShell",
36 | "request": "attach",
37 | "name": "PowerShell Attach to Host Process",
38 | "processId": "${command:PickPSHostProcess}",
39 | "runspaceId": 1
40 | },
41 | {
42 | "type": "PowerShell",
43 | "request": "launch",
44 | "name": "PowerShell Interactive Session",
45 | "cwd": ""
46 | }
47 | ]
48 | }
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | MIT License
2 |
3 | Copyright (c) 2018 Packt
4 |
5 | Permission is hereby granted, free of charge, to any person obtaining a copy
6 | of this software and associated documentation files (the "Software"), to deal
7 | in the Software without restriction, including without limitation the rights
8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9 | copies of the Software, and to permit persons to whom the Software is
10 | furnished to do so, subject to the following conditions:
11 |
12 | The above copyright notice and this permission notice shall be included in all
13 | copies or substantial portions of the Software.
14 |
15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21 | SOFTWARE.
22 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | # PowerShell Core for Linux Administrators Cookbook
5 |
6 |
7 |
8 | This is the code repository for [PowerShell Core for Linux Administrators Cookbook](https://www.packtpub.com/networking-and-servers/powershell-60-linux-administration-cookbook?utm_source=github&utm_medium=repository&utm_campaign=9781789137231 ), published by Packt.
9 |
10 | **Use PowerShell Core 6.x on Linux to automate complex, repetitive, and time-consuming tasks**
11 |
12 | ## What is this book about?
13 | PowerShell is an implementation of .NET Core. .NET Core is a cross-platform open source management framework, which adheres to POSIX standards and makes available API calls that work well with all of the major operating systems: Windows, Linux and macOS. .NET Core for Linux has been a success, because of its adherence to standards, as well as for its lightweight implementation. PowerShell extends the capabilities towards management of Linux servers as well as using containerizers such as Docker.
14 |
15 | This book covers the following exciting features:
16 | Understand the fundamentals of .NET Core and PowerShell
17 | Understand the advanced concepts of .NET Core and PowerShell
18 | Learn to write PowerShell scripts and functions with the best practices in mind
19 | Take a deep dive into administering computers locally as well as remotely using PowerShell
20 | Use PowerShell for advanced administration such as on the Cloud, Docker containers, VMware and SQL Server
21 |
22 | If you feel this book is for you, get your [copy](https://www.amazon.com/dp/1789137233) today!
23 |
24 |
26 |
27 | ## Instructions and Navigations
28 | All of the code is organized into folders. For example, ch02.
29 |
30 | The code will look like the following:
31 | ```
32 | Get-Date
33 | hostname
34 | Write-Output "Hello, $env:username!"
35 | ```
36 |
37 | **Following is what you need for this book:**
38 | PowerShell Core for Linux Administrators Cookbook is for you if you are a system administrator who wants to learn to control and automate a Linux environment with PowerShell Core 6.1. Basic knowledge of PowerShell scripting is necessary. It is assumed that you already understand how an operating system is structured and how to use the command-line interface to work with the operating system.
39 |
40 | With the following software and hardware list you can run all code files present in the book (Chapter 1-17).
41 | ### Software and Hardware List
42 | | Chapter | Software required | OS required |
43 | | -------- | ------------------------------------ | ----------------------------------- |
44 | | 1-17 | PowerShell Core 6.0/6.1 | Windows, Mac OS X, and Linux (Any) |
45 | | 1 | curl | Windows, Mac OS X, and Linux (Any) |
46 | | 2, 5, 6, 8-13, 15 | Visual Studio Code | Windows, Mac OS X, and Linux (Any) |
47 | | 3 | Visual Studio Code, PNG viewer, such as feh | Windows, Mac OS X, and Linux (Any) |
48 | | 14 | OpenSSH, WinSCP, SMTP server (Postfix) | Windows, Mac OS X, and Linux (Any) |
49 | | 16 | Visual Studio Code, .NET Core, Python, Microsoft SQL Server 2017 | Windows, Mac OS X, and Linux (Any) |
50 |
51 | We also provide a PDF file that has color images of the screenshots/diagrams used in this book. [Click here to download it](https://www.packtpub.com/sites/default/files/downloads/9781789137231_ColorImages.pdf).
52 |
53 | ### Errata
54 | * Chapter 11, recipe name: _Measuring running duration_, section name: _See also_
55 |
56 | **Software disenchantment (http://tonsky.me/blog/disenchantment/) by Nikita Prokopov, the author of the beautiful font Fira Sans**
57 |
58 | _should be_
59 |
60 | **Software disenchantment (http://tonsky.me/blog/disenchantment/) by Nikita Prokopov, the creator of the beautiful font, Fira Code**
61 |
62 |
63 | ### Related products
64 | * Learn PowerShell Core 6.0 [[Packt]](https://www.packtpub.com/networking-and-servers/learn-powershell-core-60?utm_source=github&utm_medium=repository&utm_campaign=9781788838986 ) [[Amazon]](https://www.amazon.com/dp/178883898X)
65 |
66 | * Mastering Windows PowerShell Scripting - Second Edition [[Packt]](https://www.packtpub.com/networking-and-servers/mastering-windows-powershell-scripting-second-edition?utm_source=github&utm_medium=repository&utm_campaign=9781787126305 ) [[Amazon]](https://www.amazon.com/dp/1787126307)
67 |
68 | ## Get to Know the Author
69 | **Prashanth Jayaram**
70 | is a product design and automation expert in database technology with 12 years of rich, extensive, hands-on experience in designing database solutions with next-gen database technologies. He was awarded as the second-best SQL author of 2017 for his contribution to the SQL Server technology space. He has written over 200 articles about SQL, NoSQL, PowerShell, Python, SQL on Linux, SQL on Azure, and SQL on AWS.
71 |
72 | **Ram Iyer**
73 | is an automation and application performance management specialist with about eight years of experience in enterprise IT. While ensuring that the environment in his enterprise performs optimally is his primary role, he is passionate about automation using PowerShell, and has contributed to over 60 enterprise-grade automation solutions in Windows, Microsoft Exchange, Microsoft Active Directory, Microsoft System Center, Citrix XenApp, VMware PowerCLI, and Microsoft Azure, using PowerShell. He gives back to the community by conducting training sessions in PowerShell and blogging about administration using PowerShell.
74 |
75 | ### Suggestions and Feedback
76 | [Click here](https://docs.google.com/forms/d/e/1FAIpQLSdy7dATC6QmEL81FIUuymZ0Wy9vH1jHkvpY57OiMeKGqib_Ow/viewform) if you have any feedback or suggestions.
77 |
78 |
79 | ### Download a free PDF
80 |
81 | If you have already purchased a print or Kindle version of this book, you can get a DRM-free PDF version at no cost.
Simply click on the link to claim your free PDF.
82 |
https://packt.link/free-ebook/9781789137231
--------------------------------------------------------------------------------
/best-practices.md:
--------------------------------------------------------------------------------
1 | # Best Practices Roundup
2 |
3 | Efficient administration is all about following practices which are in line with the philosophy of the tool being used. In this chapter, the best practices are re-iterated so as to ensure that the reader remembers them, along with explanations to why they’re considered best practices.
4 |
5 | ## Using cmdlets
6 |
7 | Learn all the best practices pertaining to using PowerShell cmdlets
8 |
9 | ## Using parameter aliases
10 |
11 | Learn the best practices in using parameter aliases, and how to declare and use them
12 |
13 | ## Key names for calculated properties
14 |
15 | Best practices pertaining to using calculated properties while querying information using one-liners
16 |
17 | ## Using parameters
18 |
19 | The best practices with parameters such as usage of named parameters and not using parameter aliases are covered. So is the use of parameter sets when creating functions.
20 |
21 | ## Using comments in scripts and functions
22 |
23 | This section talks about striking the right balance when it comes to using comments in scripts.
24 |
25 | ## Naming cmdlets
26 |
27 | This section is all about choosing names using approved verbs and balancing readability and length.
28 |
29 | ## Prototyping cmdlets
30 |
31 | When creating custom cmdlets, it is important that we add safety switches to system-altering capabilities.
32 |
33 | ## Using regions
34 |
35 | Use regions to enable custom code folding and create boundaries around different blocks of code
36 |
37 | ## Error handling
38 |
39 | Learn the best practices with respect to error handling
40 |
41 | ## Types of string declarations
42 |
43 | The expanding and literal strings
44 |
45 | ## Running scripts without profile
46 |
47 | Call scripts without profiles to avoid configuration conflicts
48 |
49 | ## Using objects
50 |
51 | This section aims to iterate the fact that PowerShell outputs objects and that’s where its power lies, as opposed to text.
52 |
53 | ## Declaring variables
54 |
55 | This section also talks about how to strike a balance between readability and length, but with respect to variables.
56 |
57 | ## Creating parameters
58 |
59 | Best practices pertaining to creating and declaring parameters in functions
60 |
61 | ## Writing readable scripts
62 |
63 | Best practices in code indentation, braces and flow blocks such as begin, process, end, etc.
64 |
65 | ## Using paths
66 |
67 | Sometimes using paths in scripts render them tightly coupled. Also, some usages may render the scripts unusable in some scenarios. This section gives administrators some of the right ways to use paths.
68 |
69 | ## Exporting output
70 |
71 | Remember that output from PowerShell is an object, and export the data accordingly
72 |
--------------------------------------------------------------------------------
/ch02/hello-world.ps1:
--------------------------------------------------------------------------------
1 | Write-Host "Hello, World!"
2 | $Message = "I was dot-sourced!"
--------------------------------------------------------------------------------
/ch04/Initialize-PacktPs6CoreLinuxLab.ps1:
--------------------------------------------------------------------------------
1 | function Initialize-PacktPs6CoreLinuxLab {
2 | param(
3 | # The location where the files need to be created
4 | [Parameter(Position=1)]
5 | [string]
6 | $Path = (Join-Path -Path $HOME -ChildPath random)
7 | )
8 |
9 | process {
10 | Clear-Host
11 |
12 | $CitiesPath = Join-Path -Path $Path -ChildPath cities
13 |
14 | Write-Warning "This is a quick-and-dirty function. Use this only to create your lab objects; not to learn PowerShell scripting."
15 |
16 | New-Item $CitiesPath -ItemType Directory -Force | Out-Null
17 | 'random-text.txt', 'himalayas.jpg', 'crunched-numbers.csv', 'screenshot-001.png', 'screenshot-002.png', 'screenshot-003.png', 'demo.doc', 'my-plugin.rb' | ForEach-Object { New-Item -Path (Join-Path -Path $Path -ChildPath $PSItem) -ItemType File }
18 |
19 | Write-Host 'Downloading city pages from Wikipedia'
20 | Invoke-WebRequest -Uri 'https://en.wikipedia.org/wiki/Mumbai' -OutFile (Join-Path -Path $CitiesPath -ChildPath mumbai.html)
21 | Invoke-WebRequest -Uri 'https://en.wikipedia.org/wiki/Cairo' -OutFile (Join-Path -Path $CitiesPath -ChildPath cairo.html)
22 | Invoke-WebRequest -Uri 'https://en.wikipedia.org/wiki/Dubai' -OutFile (Join-Path -Path $CitiesPath -ChildPath dubai.html)
23 | Invoke-WebRequest -Uri 'https://en.wikipedia.org/wiki/New_York_City' -OutFile (Join-Path -Path $CitiesPath -ChildPath nyc.html)
24 | Invoke-WebRequest -Uri 'https://en.wikipedia.org/wiki/Paris' -OutFile (Join-Path -Path $CitiesPath -ChildPath paris.html)
25 |
26 | Write-Host 'Downloading some multimedia content'
27 | Invoke-WebRequest -Uri 'https://farm3.staticflickr.com/2912/33114379033_5bdee305fa_h.jpg?fdl=1' -OutFile (Join-Path -Path $Path -ChildPath volcano.jpg)
28 | Invoke-WebRequest -Uri 'https://farm8.staticflickr.com/7561/28010104522_f9b54051da_h.jpg?fdl=1' -OutFile (Join-Path -Path $Path -ChildPath coffee.jpg)
29 | Invoke-WebRequest -Uri 'https://player.vimeo.com/external/121142413.hd.mp4?s=55cd0e066b1b588b4121a6280da4a9d84bc97947&profile_id=119&oauth2_token_id=57447761&download=1' -OutFile (Join-Path -Path $Path -ChildPath matrix-like-wm.mp4)
30 | Invoke-WebRequest -Uri 'http://feeds.soundcloud.com/stream/265848849-wowamusik-piratosbeta.mp3' -OutFile (Join-Path -Path $Path -ChildPath piratos-wowa.me.mp3)
31 | Invoke-WebRequest -Uri 'https://unsplash.com/photos/NgtK0TdGT0Y/download?force=true' -OutFile (Join-Path -Path $Path -ChildPath bangalore.jpg)
32 |
33 | Write-Warning "If you encountered errors during the download, chances are that the content is missing from the original sources. Any content would do for the lab; download your own if you want to."
34 |
35 | Write-Host "`n`nCredits:`nCristian Ungureanu (http://mystock.photos/author/cristi/) for volcano.jpg and coffee.jpg`nSean Do (https://www.videezy.com/members/everywheresean) for matrix-like-wm.mp4`nWOWA (http://www.wowa.me/) for piratos-wowa.me.mp3`nAatur Harsh (https://unsplash.com/@aaturharsh) for bangalore.jpg`n"
36 | }
37 | }
38 |
39 | Initialize-PacktPs6CoreLinuxLab
--------------------------------------------------------------------------------
/ch05/6.2-dotnetcore-obj.ps1:
--------------------------------------------------------------------------------
1 | class Person {
2 | [string]$Name
3 | [Int32]$Age
4 | [int32]$Salary
5 |
6 | Person () {}
7 |
8 | Person ([string]$Name, [int32]$Age) {
9 | $this.Name = $Name
10 | $this.Age = $Age
11 | }
12 |
13 | [int32] sal ([int32]$Salary, [int32]$Comm) {
14 | return $Salary * $Comm
15 | }
16 | }
--------------------------------------------------------------------------------
/ch05/6.6-CustomTypes.ps1xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | System.IO.FileInfo
5 |
6 |
7 | Modified
8 | LastWriteTime
9 |
10 |
11 | Age
12 | [math]::Round(((Get-Date) - $this.LastWriteTime).TotalDays)
13 |
14 |
15 |
16 |
--------------------------------------------------------------------------------
/ch06/03-input-file-expanding.txt:
--------------------------------------------------------------------------------
1 | /home/ram/dir-01/dir-07/dir-09/dir-13/
2 | /home/ram/dir-02/dir-05/dir-06/
3 | /home/ram/dir-03/dir-08/dir-10/
4 | /home/ram/dir-04/dir-11/dir-12/dir-14/
5 | /home/ram/dir-04/dir-11/dir-12/dir-15/
6 | /home/ram/dir-04/dir-11/dir-12/dir-16/
7 | /home/ram/dir-04/dir-11/dir-12/dir-17/
8 | /home/ram/dir-04/dir-11/dir-12/dir-18/dir-19/
9 | /home/ram/dir-04/dir-11/dir-12/dir-18/dir-20/
10 |
--------------------------------------------------------------------------------
/ch06/03-input-file.txt:
--------------------------------------------------------------------------------
1 | ./dir-01/dir-07/dir-09/dir-13/
2 | ./dir-02/dir-05/dir-06/
3 | ./dir-03/dir-08/dir-10/
4 | ./dir-04/dir-11/dir-12/dir-14/
5 | ./dir-04/dir-11/dir-12/dir-15/
6 | ./dir-04/dir-11/dir-12/dir-16/
7 | ./dir-04/dir-11/dir-12/dir-17/
8 | ./dir-04/dir-11/dir-12/dir-18/dir-19/
9 | ./dir-04/dir-11/dir-12/dir-18/dir-20/
10 |
--------------------------------------------------------------------------------
/ch06/05-Get-TravelArticles.ps1:
--------------------------------------------------------------------------------
1 | $CsvImport = Import-Csv ./05-sitelist.csv
2 | if ($CsvImport.Name -contains 'BBC') {
3 | $Uri = ($CsvImport | Where-Object Name -EQ 'BBC').HomeURL
4 | (Invoke-WebRequest -Uri $Uri).Links |
5 | Where-Object href -match '/travel/.+' |
6 | Select-Object -ExpandProperty href -Unique
7 | }
8 | Remove-Item ./05-sitelist.csv
--------------------------------------------------------------------------------
/ch06/05-sitelist.csv:
--------------------------------------------------------------------------------
1 | Name,HomeURL
2 | BBC,http://www.bbc.com/
3 | Reuters,https://in.reuters.com/
4 | Associated Press,https://www.ap.org/en-gb/
5 | Philippine News,http://www.pna.gov.ph/
6 | Al Jazeera,http://www.aljazeera.net/portal
7 | Bloomberg,https://www.bloomberg.com/
8 | The Hindu,https://www.thehindu.com/
--------------------------------------------------------------------------------
/ch06/06-puregfm.md:
--------------------------------------------------------------------------------
1 | # Command line, anybody?
2 |
3 | We're Windows people. We love the GUI. We don't use the boring plain window with grey text. All that is so yesterday, aye? We are more used to moving the mouse, clicking at places, and then touch the keyboard only when we have something to type. We love that experience, be it Aero™ effect, or some other sassy visuals. Command line, again, is so yesterday.
4 |
5 | Fair? Perhaps. Efficient?
6 |
7 | > The console is your friend.
8 |
9 | We're IT folks. We're engineers. We care about efficiency. I do, and I'm sure most of you do. I mean, think about it: the time taken by you to copy-paste the file names of files in a certain directory can be used to get a cup of coffee, if you could offload it to something more efficient, don't you think? (No \*nix jabs, please!) Literally speaking, PowerShell can do the task of listing out all the file names in a certain directory and put the content in your clipboard in a matter of three seconds (including the time taken to write the command). Compare that with `Right-click`, look for `Rename`, click on `Rename` to get the file name selected, `Right-click` again and select `Copy`. Take the pointer to the task bar, click on the icon for the file... OK, I'm tired already. A better way? Let's say you do a `cd C:\Users\AwesomeMan` in your PowerShell console, and you want to list out all the contents in that folder.
10 |
11 | ```powershell
12 | Get-ChildItem | select Name | clip
13 | ```
14 |
15 | Less than three seconds. Seriously, try it! All you have to do now is go to where you wanted the file names to be pasted (email, perhaps), and press `Ctrl+V`.
16 |
17 | My point is, the console is our friend. And friends, we embrace. Embrace the console, give it a shot. You'll get addicted to the efficiency and the speed.
18 |
19 | It's now time to download Windows PowerShell.
20 |
21 | It will ask you for a restart, so be prepared. Once it's done, you're all set to follow this blog. If you'd like to get updates very time a post is added, follow me on Facebook.
22 |
23 | # Basics of Windows
24 |
25 | Among all the jazz of ClearType fonts and graphics, we often take for granted what is actually some serious task—running the hardware of a computer. Ever wondered how different the actual working of a computer is, compared to what we see on the screen? In reality, it's overwhelmingly difficult to imagine how computers work, especially today. It's hard to believe that two voltage-based states of a bunch of transistors and gates are able to show to us what we see on the screen. These things finish off some tasks in seconds, that humans would usually take anywhere from a few minutes to several days to accomplish.
26 |
27 | To try to fathom what happens inside a computer (and this is of some importance), let's go back to the days of DOS. As we all know from common sense today, a computer is nothing but a bunch of hardware which runs some software to get work done. But how the software talks to the hardware is something that we need to know.
28 |
29 | Imagine the operating system (the piece of software which runs a computer) to be made of two primary layers:
30 |
31 | - The kernel
32 | - The shell
33 |
34 | In simple terms, the kernel talks to the hardware, and is responsible for all the interactions the operating system has with the hardware. The shell, on the other hand, is responsible for interactions with the user. So this is how a computer should look like, in general:
35 |
36 | - User
37 | - Shell
38 | - OS libraries
39 | - Kernel
40 | - Hardware
41 |
42 | So there's the hardware. Then, there's the kernel that is the mediator between the hardware and the shell. And then there's the shell, which is the mediator between the kernel and the user.
43 |
44 | In the interest of simplicity of the interface, Microsoft, for one, made things in such a way that applications sat on top of the shell, and the applications interacted with the users. A few examples for these applications would be simple things like `ping` and `telnet`, and more complex things such as `Adobe Photoshop`. So the shell was not really exposed to the user. There was the shell, the command line interface (or CLI) tools. When the GUI was made, the GUI sat along with the CLI.
45 |
46 | If my memory is right, DOS booted up this way:
47 |
48 | - The hardware was powered on, and the Basic Input Output System (BIOS) ran Power-On Self-Test (POST)
49 | - Once POST was complete, the BIOS looked for an operating system at the first sector of the first track of the first disk
50 | - If an OS entry was found, BIOS started loading the OS
51 | - First, a file called `io.sys` was loaded onto the RAM
52 | - Then, `msdos.sys` was loaded
53 | - The file, `command.com` was loaded onto the RAM
54 | - BIOS relinquished control to MS-DOS, and the computer was ready for operation.
55 |
56 | While I'm not entirely sure of this, this does seem like the same sequence of kernel, shell, and the CLI.
57 |
58 | The problem was that the applications that were built to run on top of the CLI had access only to the CLI. They had to talk to the CLI, the CLI then spoke to the shell, which in turn spoke to the kernel, which then spoke to the hardware. Whew!
59 |
60 | Now think of it as a game of Chinese Whispers. Funny, right?
61 |
62 | So there were problems with this approach, in that the output was not always usable for programming. The efficiency dropped significantly, and calling the classes within the internal framework was more than challenging.
63 |
64 | The post is quite long for a read. Let's give ourselves a break here, and resume in the next post.
65 |
66 | # Enter PowerShell
67 |
68 | In the last post, we spoke about how it was a challenge to get data using the CLI, for programmatic use. It was a challenge, but the concept was not bad. After all, computers started off being commanded using the text interface. The CLI, though, got some job done, of course. There are more than a boatload of applications that can run purely from the command line. But there were challenges:
69 |
70 | - Too much to remember
71 | - Not exactly systematic or uniform
72 | - Getting help seemed like juvenile text chat (use of `/?`)
73 | - Not-very-useful plain text output
74 |
75 | Overall, the Windows CLI had started to seem like a big mess people could not handle anymore. Aside from the security issues that were a weakness with Windows, Microsoft now had more reasons to go for a paradigm shift. In 2006, they finally unveiled the first version of what is today, one of the best things Microsoft ever created: Windows PowerShell. They made it available for Windows XP starting Service Pack 3, and Windows Vista. Windows 7 and all subsequent versions of Windows shipped with PowerShell.
76 |
77 | PowerShell managed to address all of the aforementioned problems. Also, PowerShell sat a level closer to the hardware. PowerShell is an extension of the Windows shell itself; it sits right on top of the .NET libraries. More on that later.
78 |
79 | Apart from the proximity to the libraries, here's why PowerShell is awesome on Windows:
80 |
81 | ### Remember less, use logic
82 |
83 | PowerShell sounds like English. When we need water, we say, "Could you please *get* me some *water*?" Notice the verb, the noun, and the sequence in which they're placed. If PowerShell ever got the capability of getting water, the command (or cmdlet—pronounce: command-let) would be, `Get-Water`. This way, we need to *remember less*. So if I want a list of processes running on my PC, I would just have to say, `Get-Process`. Can it get any simpler?
84 |
85 | ### Systematic commands
86 |
87 | With PowerShell, Microsoft (and the community) introduced the concept of *Approved Verbs* (type in `Get-Verb` in the PowerShell window), wherein, you have to choose from a predefined set of verbs to create your cmdlets in PowerShell. So if I wanted PowerShell to get me some water, I could only say, `Get-Water`, and never `Bring-Water`. It's just about a little foresight: this way, the first point would be reinforced.
88 |
89 | ### Finding commands simplified
90 |
91 | That's right. Now if you want to get a command that kind of, say, sets the date, I can find my command either using the verb or the noun:
92 |
93 | ```powershell
94 | Get-Command -Noun 'Date'
95 | ```
96 |
97 | Or you could write this to be more specific
98 |
99 | ```powershell
100 | Get-Command -Verb 'Set' -Noun 'Date'
101 | ```
102 |
103 | Or you could simply take a guess and say,
104 |
105 | ```powershell
106 | Get-Command -Name 'Get-Date'
107 | ```
108 |
109 | Try it out! Experiment. Since the article is about 500 words, let's call it a day. We'll meet tomorrow to know more.
110 |
111 | # Sense, sensibility and flexibility
112 |
113 | Yesterday. The reason I'm asking for the upgrade is that some of the things I'm going to post in the future will depend on PowerShell 3.0. The link given is for version 5.0. If you feel that you may already be on a version higher than 3.0, then run the following command to ensure you are.
114 |
115 | ```powershell
116 | $PsVersionTable
117 | ```
118 |
119 | Look for the value for `PSVersion`. If it is higher than 3.0, it's not *necessary* that you upgrade PowerShell on your computer, although, I would recommend the upgrade. What's there to lose, it's free!
120 |
121 | Coming back to sensibility, the output that PowerShell gives you is more sensible, and... *computable*.
122 |
123 | What makes it better is that if something isn't sensible right away, you can *make it sensible*. For example, run the following command:
124 |
125 | ```powershell
126 | Get-ChildItem
127 | ```
128 |
129 | You see a column called `Length`. It wouldn't make sense to some people right off the bat. While it just means "size", people who are not very familiar with the technical terminology would not understand it at the first shot. The fix? Just use *Calculated Properties*!
130 |
131 | Here:
132 |
133 | ```powershell
134 | Get-ChildItem | Select-Object Name, @{Name="Size(MB)";Expression={$_.Length / 1MB}}
135 | ```
136 |
137 | Did you run that? No? Please open the console and run it.
138 |
139 | Cool, right? Calculated properties are nothing but values that are _manipulated_. You can simply tell PowerShell that you want the column renamed as "Size(MB)". As long as the name is in quotes, you can have spaces if you want, but I'd recommend against it. You'll understand when we start referring to specific properties from the output. We'll talk about it in more detail then.
140 |
141 | ### Easier help
142 |
143 | Before we wind up for the day, let's look at how getting help is no more juvenile talk, but a pleasant experience. When you want to get some help, all you say is... That's right, `Get-Help`! When you need help with the command to fetch the services running on your PC, you would simply say,
144 |
145 | ```powershell
146 | Get-Command -Verb 'Get' -Noun '*service*'
147 |
148 | Get-Help Get-Service
149 |
150 | Get-Help Get-Service -Full
151 |
152 | Get-Help Get-Service -Examples
153 | ```
154 |
155 |
156 | Try out those commands. Get your hands dirty in PowerShell. There's something called as muscle memory; it's what helps you type, without having to constantly look at the keyboard, also, how we type `Get-Help` instead of `Get Help`. Type the commands. Go on. Let's meet up again tomorrow!
157 |
158 | # Familiarising the windows
159 |
160 | We saw some cool stuff in the past couple of posts on PowerShell. Some of us probably even found it ironic that there were certain things in the commands given in the post, which did not make much sense, while everything in PowerShell *should* have made sense.
161 |
162 | Worry not. We're on the next step of our PowerShell journey.
163 |
164 | Before we proceed, we need to know a few things about PowerShell, and how to use it. So let's simply talk about the different PowerShell consoles we have, and which one to use when.
165 |
166 | In general, I'd say, there's no hard and fast rule that only a certain type of console can be used in a certain situation. It's a matter of convenience, personal preferences and popular choices. And popular choices, when it comes to tech stuff, are usually good choices in general. No, please, no, this is not the time to talk about how Androids are highly popular but not necessarily a good choice. There are various factors there. And it's a never-ending debate.
167 |
168 | Back to using PowerShell. Technically speaking, if you're running a 64-bit (x64) computer, there are eight different kinds of PowerShell windows. If you're running a 32-bit (x86) computer, there are four.
169 |
170 | * The Console
171 | * Windows PowerShell
172 | * Windows PowerShell (x86)
173 | * The administrator] window for both
174 | * The Integrated Scripting Environment (ISE)
175 | * Windows PowerShell ISE
176 | * Windows PowerShell ISE (x86)
177 | * The administrator] window for both
178 |
179 | Please note that on x86 computers, there would be no Windows PowerShell (x86) because their PowerShell would anyway be x86, eliminating the need for another x86-type window. x64 computers, on the other hand, have x64 windows by default, and can launch an x86 window if needed, although, I can't think of a practical reason to do it.
180 |
181 | ### The console
182 |
183 | The console seems very similar to the command prompt window. This does not have much options. This window is a lightweight one, and is used when you have to run commands line-by-line, just to fetch some basic information (or, like, restart your computer through command). When you hit the `Enter` key after a command, the command executes (duh, right?), and if you want to go to the next line without running the command, you have to do a `Shift+Enter`. So, as I said, this is used primarily to run commands, and not write scripts. In this window, you enter the command, and the output appears right below the command.
184 |
185 | The window colours are a little different from the command prompt to give us a visual cue that this is a PowerShell window. Although, it's worth noting that most `cmd` commands run on the PowerShell console. Some options and the way the arguments are passed may differ in cases where the command itself is an alias to an underlying PowerShell cmdlet.
186 |
187 | Whoa, whoa, hold on! What did you say? What alias?
188 |
189 | Don't worry about it. I'll remember to talk about this in the very next post, if possible. For now, just remember that most of CMD commands can run on PowerShell.
190 |
191 | ### The Integrated Scripting Environment
192 |
193 | The PowerShell ISE, as its name suggests, is a scripting-and-debugging environment. This is heavier compared to the PowerShell command console. The ISE is feature-rich, with Intellisense™, command pane showing you all available commands, add-ons and things like that.
194 |
195 | The older versions of PowerShell ISE had three sections where action happened:
196 |
197 | * The script pane, where we wrote scripts
198 | * The output pane, where the output was shown
199 | * The command pane, which was the same as the command console
200 |
201 | Today's PowerShell ISE combines the second and the third panes into one. So we have only the script pane and the console. Again, the console is used to run commands by hitting the `Enter` key, and viewing output. The scripting pane is to write PowerShell scripts. Here, hitting `Enter` just takes you to the next line. You have to run the script by hitting the `Run` key, and you can then break into the debugger to debug your scripts and all.
202 |
203 | As you can see, this is a more advanced way of using PowerShell—in fact, I'd daresay that this is *the* way to use PowerShell! But of course, if I just want to run `Restart-Computer`, I wouldn't launch a session of ISE. By the time it loads, the computer restart could begin, if done through the console.
204 |
205 | > Did you know that you can convert a CMD window to a PowerShell command window? Open CMD, type in `PowerShell` and hit `Enter`. Notice the prompt change!
206 |
207 | That's all for today! Play around with the console and get used to how it looks and all. As a bonus, if you're into code highlight themes and all, check out this repository of PowerShell ISE themes. Enjoy!
--------------------------------------------------------------------------------
/ch06/06-rawcontent.txt:
--------------------------------------------------------------------------------
1 | ---
2 | title: Command line, anybody?
3 | date: '2017-04-01 21:17'
4 | tags:
5 | - windows
6 | category: tyro
7 | ---
8 |
9 | We're Windows people. We love the GUI. We don't use the boring plain window with grey text. All that is so yesterday, aye? We are more used to moving the mouse, clicking at places, and then touch the keyboard only when we have something to type. We love that experience, be it Aero™ effect, or some other sassy visuals. Command line, again, is so yesterday.
10 |
11 | Fair? Perhaps. Efficient?
12 |
13 | > The console is your friend.
14 |
15 | We're IT folks. We're engineers. We care about efficiency. I do, and I'm sure most of you do. I mean, think about it: the time taken by you to copy-paste the file names of files in a certain directory can be used to get a cup of coffee, if you could offload it to something more efficient, don't you think? (No \*nix jabs, please!) Literally speaking, PowerShell can do the task of listing out all the file names in a certain directory and put the content in your clipboard in a matter of three seconds (including the time taken to write the command). Compare that with `Right-click`, look for `Rename`, click on `Rename` to get the file name selected, `Right-click` again and select `Copy`. Take the pointer to the task bar, click on the icon for the file... OK, I'm tired already. A better way? Let's say you do a `cd C:\Users\AwesomeMan` in your PowerShell console, and you want to list out all the contents in that folder.
16 |
17 | ```powershell
18 | Get-ChildItem | select Name | clip
19 | ```
20 |
21 | Less than three seconds. Seriously, try it! All you have to do now is go to where you wanted the file names to be pasted (email, perhaps), and press `Ctrl+V`.
22 |
23 | My point is, the console is our friend. And friends, we embrace. Embrace the console, give it a shot. You'll get addicted to the efficiency and the speed.
24 |
25 | It's now time to download Windows PowerShell.
26 |
27 | It will ask you for a restart, so be prepared. Once it's done, you're all set to follow this blog. If you'd like to get updates very time a post is added, follow me on Facebook.
28 |
29 | ---
30 | title: Basics of Windows
31 | date: '2017-04-03 12:00'
32 | tags:
33 | - windows
34 | category: tyro
35 | ---
36 |
37 | Among all the jazz of ClearType fonts and graphics, we often take for granted what is actually some serious task—running the hardware of a computer. Ever wondered how different the actual working of a computer is, compared to what we see on the screen? In reality, it's overwhelmingly difficult to imagine how computers work, especially today. It's hard to believe that two voltage-based states of a bunch of transistors and gates are able to show to us what we see on the screen. These things finish off some tasks in seconds, that humans would usually take anywhere from a few minutes to several days to accomplish.
38 |
39 | To try to fathom what happens inside a computer (and this is of some importance), let's go back to the days of DOS. As we all know from common sense today, a computer is nothing but a bunch of hardware which runs some software to get work done. But how the software talks to the hardware is something that we need to know.
40 |
41 | Imagine the operating system (the piece of software which runs a computer) to be made of two primary layers:
42 |
43 | - The kernel
44 | - The shell
45 |
46 | In simple terms, the kernel talks to the hardware, and is responsible for all the interactions the operating system has with the hardware. The shell, on the other hand, is responsible for interactions with the user. So this is how a computer should look like, in general:
47 |
48 | - User
49 | - Shell
50 | - OS libraries
51 | - Kernel
52 | - Hardware
53 |
54 | So there's the hardware. Then, there's the kernel that is the mediator between the hardware and the shell. And then there's the shell, which is the mediator between the kernel and the user.
55 |
56 | In the interest of simplicity of the interface, Microsoft, for one, made things in such a way that applications sat on top of the shell, and the applications interacted with the users. A few examples for these applications would be simple things like `ping` and `telnet`, and more complex things such as `Adobe Photoshop`. So the shell was not really exposed to the user. There was the shell, the command line interface (or CLI) tools. When the GUI was made, the GUI sat along with the CLI.
57 |
58 | If my memory is right, DOS booted up this way:
59 |
60 | - The hardware was powered on, and the Basic Input Output System (BIOS) ran Power-On Self-Test (POST)
61 | - Once POST was complete, the BIOS looked for an operating system at the first sector of the first track of the first disk
62 | - If an OS entry was found, BIOS started loading the OS
63 | - First, a file called `io.sys` was loaded onto the RAM
64 | - Then, `msdos.sys` was loaded
65 | - The file, `command.com` was loaded onto the RAM
66 | - BIOS relinquished control to MS-DOS, and the computer was ready for operation.
67 |
68 | While I'm not entirely sure of this, this does seem like the same sequence of kernel, shell, and the CLI.
69 |
70 | The problem was that the applications that were built to run on top of the CLI had access only to the CLI. They had to talk to the CLI, the CLI then spoke to the shell, which in turn spoke to the kernel, which then spoke to the hardware. Whew!
71 |
72 | Now think of it as a game of Chinese Whispers. Funny, right?
73 |
74 | So there were problems with this approach, in that the output was not always usable for programming. The efficiency dropped significantly, and calling the classes within the internal framework was more than challenging.
75 |
76 | The post is quite long for a read. Let's give ourselves a break here, and resume in the next post.
77 |
78 | ---
79 | title: Enter PowerShell
80 | date: '2017-04-04 12:00'
81 | tags:
82 | - windows
83 | - powershell
84 | category: tyro
85 | ---
86 |
87 | In the last post, we spoke about how it was a challenge to get data using the CLI, for programmatic use. It was a challenge, but the concept was not bad. After all, computers started off being commanded using the text interface. The CLI, though, got some job done, of course. There are more than a boatload of applications that can run purely from the command line. But there were challenges:
88 |
89 | - Too much to remember
90 | - Not exactly systematic or uniform
91 | - Getting help seemed like juvenile text chat (use of `/?`)
92 | - Not-very-useful plain text output
93 |
94 | Overall, the Windows CLI had started to seem like a big mess people could not handle anymore. Aside from the security issues that were a weakness with Windows, Microsoft now had more reasons to go for a paradigm shift. In 2006, they finally unveiled the first version of what is today, one of the best things Microsoft ever created: Windows PowerShell. They made it available for Windows XP starting Service Pack 3, and Windows Vista. Windows 7 and all subsequent versions of Windows shipped with PowerShell.
95 |
96 | PowerShell managed to address all of the aforementioned problems. Also, PowerShell sat a level closer to the hardware. PowerShell is an extension of the Windows shell itself; it sits right on top of the .NET libraries. More on that later.
97 |
98 | Apart from the proximity to the libraries, here's why PowerShell is awesome on Windows:
99 |
100 | ### Remember less, use logic
101 |
102 | PowerShell sounds like English. When we need water, we say, "Could you please *get* me some *water*?" Notice the verb, the noun, and the sequence in which they're placed. If PowerShell ever got the capability of getting water, the command (or cmdlet—pronounce: command-let) would be, `Get-Water`. This way, we need to *remember less*. So if I want a list of processes running on my PC, I would just have to say, `Get-Process`. Can it get any simpler?
103 |
104 | ### Systematic commands
105 |
106 | With PowerShell, Microsoft (and the community) introduced the concept of *Approved Verbs* (type in `Get-Verb` in the PowerShell window), wherein, you have to choose from a predefined set of verbs to create your cmdlets in PowerShell. So if I wanted PowerShell to get me some water, I could only say, `Get-Water`, and never `Bring-Water`. It's just about a little foresight: this way, the first point would be reinforced.
107 |
108 | ### Finding commands simplified
109 |
110 | That's right. Now if you want to get a command that kind of, say, sets the date, I can find my command either using the verb or the noun:
111 |
112 | ```powershell
113 | Get-Command -Noun 'Date'
114 | ```
115 |
116 | Or you could write this to be more specific
117 |
118 | ```powershell
119 | Get-Command -Verb 'Set' -Noun 'Date'
120 | ```
121 |
122 | Or you could simply take a guess and say,
123 |
124 | ```powershell
125 | Get-Command -Name 'Get-Date'
126 | ```
127 |
128 | Try it out! Experiment. Since the article is about 500 words, let's call it a day. We'll meet tomorrow to know more.
129 |
130 | ---
131 | title: Sense, sensibility and flexibility
132 | date: '2017-04-05 12:00'
133 | tags:
134 | - windows
135 | - powershell
136 | category: tyro
137 | ---
138 |
139 | Yesterday. The reason I'm asking for the upgrade is that some of the things I'm going to post in the future will depend on PowerShell 3.0. The link given is for version 5.0. If you feel that you may already be on a version higher than 3.0, then run the following command to ensure you are.
140 |
141 | ```powershell
142 | $PsVersionTable
143 | ```
144 |
145 | Look for the value for `PSVersion`. If it is higher than 3.0, it's not *necessary* that you upgrade PowerShell on your computer, although, I would recommend the upgrade. What's there to lose, it's free!
146 |
147 | Coming back to sensibility, the output that PowerShell gives you is more sensible, and... *computable*.
148 |
149 | What makes it better is that if something isn't sensible right away, you can *make it sensible*. For example, run the following command:
150 |
151 | ```powershell
152 | Get-ChildItem
153 | ```
154 |
155 | You see a column called `Length`. It wouldn't make sense to some people right off the bat. While it just means "size", people who are not very familiar with the technical terminology would not understand it at the first shot. The fix? Just use *Calculated Properties*!
156 |
157 | Here:
158 |
159 | ```powershell
160 | Get-ChildItem | Select-Object Name, @{Name="Size(MB)";Expression={$_.Length / 1MB}}
161 | ```
162 |
163 | Did you run that? No? Please open the console and run it.
164 |
165 | Cool, right? Calculated properties are nothing but values that are _manipulated_. You can simply tell PowerShell that you want the column renamed as "Size(MB)". As long as the name is in quotes, you can have spaces if you want, but I'd recommend against it. You'll understand when we start referring to specific properties from the output. We'll talk about it in more detail then.
166 |
167 | ### Easier help
168 |
169 | Before we wind up for the day, let's look at how getting help is no more juvenile talk, but a pleasant experience. When you want to get some help, all you say is... That's right, `Get-Help`! When you need help with the command to fetch the services running on your PC, you would simply say,
170 |
171 | ```powershell
172 | Get-Command -Verb 'Get' -Noun '*service*'
173 |
174 | Get-Help Get-Service
175 |
176 | Get-Help Get-Service -Full
177 |
178 | Get-Help Get-Service -Examples
179 | ```
180 |
181 |
182 | Try out those commands. Get your hands dirty in PowerShell. There's something called as muscle memory; it's what helps you type, without having to constantly look at the keyboard, also, how we type `Get-Help` instead of `Get Help`. Type the commands. Go on. Let's meet up again tomorrow!
183 |
184 | ---
185 | title: Familiarising the windows
186 | date: '2017-04-06 12:00'
187 | tags: powershell
188 | category: tyro
189 | ---
190 |
191 | We saw some cool stuff in the past couple of posts on PowerShell. Some of us probably even found it ironic that there were certain things in the commands given in the post, which did not make much sense, while everything in PowerShell *should* have made sense.
192 |
193 | Worry not. We're on the next step of our PowerShell journey.
194 |
195 | Before we proceed, we need to know a few things about PowerShell, and how to use it. So let's simply talk about the different PowerShell consoles we have, and which one to use when.
196 |
197 | In general, I'd say, there's no hard and fast rule that only a certain type of console can be used in a certain situation. It's a matter of convenience, personal preferences and popular choices. And popular choices, when it comes to tech stuff, are usually good choices in general. No, please, no, this is not the time to talk about how Androids are highly popular but not necessarily a good choice. There are various factors there. And it's a never-ending debate.
198 |
199 | Back to using PowerShell. Technically speaking, if you're running a 64-bit (x64) computer, there are eight different kinds of PowerShell windows. If you're running a 32-bit (x86) computer, there are four.
200 |
201 | * The Console
202 | * Windows PowerShell
203 | * Windows PowerShell (x86)
204 | * The administrator] window for both
205 | * The Integrated Scripting Environment (ISE)
206 | * Windows PowerShell ISE
207 | * Windows PowerShell ISE (x86)
208 | * The administrator] window for both
209 |
210 | Please note that on x86 computers, there would be no Windows PowerShell (x86) because their PowerShell would anyway be x86, eliminating the need for another x86-type window. x64 computers, on the other hand, have x64 windows by default, and can launch an x86 window if needed, although, I can't think of a practical reason to do it.
211 |
212 | ### The console
213 |
214 | The console seems very similar to the command prompt window. This does not have much options. This window is a lightweight one, and is used when you have to run commands line-by-line, just to fetch some basic information (or, like, restart your computer through command). When you hit the `Enter` key after a command, the command executes (duh, right?), and if you want to go to the next line without running the command, you have to do a `Shift+Enter`. So, as I said, this is used primarily to run commands, and not write scripts. In this window, you enter the command, and the output appears right below the command.
215 |
216 | The window colours are a little different from the command prompt to give us a visual cue that this is a PowerShell window. Although, it's worth noting that most `cmd` commands run on the PowerShell console. Some options and the way the arguments are passed may differ in cases where the command itself is an alias to an underlying PowerShell cmdlet.
217 |
218 | Whoa, whoa, hold on! What did you say? What alias?
219 |
220 | Don't worry about it. I'll remember to talk about this in the very next post, if possible. For now, just remember that most of CMD commands can run on PowerShell.
221 |
222 | ### The Integrated Scripting Environment
223 |
224 | The PowerShell ISE, as its name suggests, is a scripting-and-debugging environment. This is heavier compared to the PowerShell command console. The ISE is feature-rich, with Intellisense™, command pane showing you all available commands, add-ons and things like that.
225 |
226 | The older versions of PowerShell ISE had three sections where action happened:
227 |
228 | * The script pane, where we wrote scripts
229 | * The output pane, where the output was shown
230 | * The command pane, which was the same as the command console
231 |
232 | Today's PowerShell ISE combines the second and the third panes into one. So we have only the script pane and the console. Again, the console is used to run commands by hitting the `Enter` key, and viewing output. The scripting pane is to write PowerShell scripts. Here, hitting `Enter` just takes you to the next line. You have to run the script by hitting the `Run` key, and you can then break into the debugger to debug your scripts and all.
233 |
234 | As you can see, this is a more advanced way of using PowerShell—in fact, I'd daresay that this is *the* way to use PowerShell! But of course, if I just want to run `Restart-Computer`, I wouldn't launch a session of ISE. By the time it loads, the computer restart could begin, if done through the console.
235 |
236 | > Did you know that you can convert a CMD window to a PowerShell command window? Open CMD, type in `PowerShell` and hit `Enter`. Notice the prompt change!
237 |
238 | That's all for today! Play around with the console and get used to how it looks and all. As a bonus, if you're into code highlight themes and all, check out this repository of PowerShell ISE themes. Enjoy!
--------------------------------------------------------------------------------
/ch06/07-input.csv:
--------------------------------------------------------------------------------
1 | Path,Retention,Extension,Exclusion
2 | /home/coolapp/logs,7,.log,/home/coolapp/logs/devicelogs;/home/coolapp/logs/install
--------------------------------------------------------------------------------
/ch06/07-split-input.ps1:
--------------------------------------------------------------------------------
1 | $PathInfo = Import-Csv './ch06/07-input.csv'
2 |
3 | # Looping construct here
4 | $Path = $PathInfo.Path
5 | $RetentionDays = $PathInfo.Retention
6 | $Extension = $PathInfo.Extension
7 | $Exclusion = $PathInfo.Exclusion
8 | # Eng loop
9 |
10 | $ExclusionPaths = $Exclusion -split ';'
11 |
12 | # Some code block to handle deletion and other things
13 |
14 | Write-Host "These $($ExclusionPaths.Count) paths will be excluded from deletion: $($ExclusionPaths -join ', ')"
--------------------------------------------------------------------------------
/ch06/08-details.txt:
--------------------------------------------------------------------------------
1 | Mr
2 | Bilbo Baggins
3 | 9149-4554-2127-8685
4 | Bag End, The Shire, Hobbiton, Middle Earth
5 | bilbo.baggins@middlearthmail.me
6 | 0069928789312
7 | 8472
--------------------------------------------------------------------------------
/ch06/08-mailto.txt:
--------------------------------------------------------------------------------
1 | Send email
--------------------------------------------------------------------------------
/ch07/02.1-Get-WeekDay-if-else.ps1:
--------------------------------------------------------------------------------
1 | $Date = Get-Date
2 |
3 | if ($Date.DayOfWeek -in 'Saturday', 'Sunday') {
4 | Write-Host 'We party on weekends!' -BackgroundColor Yellow -ForegroundColor Black
5 | }
6 | elseif ($Date.DayOfWeek -eq 'Wednesday') {
7 | Write-Host 'Half the week is over, and I want to do so much more!'
8 | }
9 | else {
10 | Write-Host 'Work is worship. Ahem!'
11 | }
--------------------------------------------------------------------------------
/ch07/02.2-Get-Weekday-switch-case.ps1:
--------------------------------------------------------------------------------
1 | $Date = Get-Date
2 |
3 | switch ($Date.DayOfWeek) {
4 | 'Monday' { Write-Output 'Red' }
5 | 'Tuesday' { Write-Output 'Violet' }
6 | 'Wednesday' { Write-Output 'Indigo' }
7 | 'Thursday' { Write-Output 'Blue' }
8 | 'Friday' { Write-Output 'Green' }
9 | Default { Write-Output 'Orange' }
10 | }
--------------------------------------------------------------------------------
/ch07/03-Wait-BeforeDressCode.ps1:
--------------------------------------------------------------------------------
1 | $Date = Get-Date
2 |
3 | if ($Date.DayOfWeek -in 'Saturday', 'Sunday') {
4 | Write-Host 'We party on weekends!' -BackgroundColor Yellow -ForegroundColor Black
5 | }
6 | elseif ($Date.DayOfWeek -eq 'Wednesday') {
7 | Write-Host 'Half the week is over, and I want to do so much more!'
8 | }
9 | else {
10 | Write-Host 'Work is worship. Ahem!'
11 | }
12 |
13 | Start-Sleep -Seconds 5
14 |
15 | switch ($Date.DayOfWeek) {
16 | 'Monday' { Write-Output 'Wear red.'; break }
17 | 'Tuesday' { Write-Output 'Wear violet.'; break }
18 | 'Wednesday' { Write-Output 'Wear indigo.'; break }
19 | 'Thursday' { Write-Output 'Wear blue.'; break }
20 | 'Friday' { Write-Output 'Wear green.'; break }
21 | Default { Write-Output 'Poor you, working today. Wear orange.'; break }
22 | }
--------------------------------------------------------------------------------
/ch07/04-Write-Greetings.ps1:
--------------------------------------------------------------------------------
1 | $GuestsRaw = Read-Host "Enter the guest names, separated by commas"
2 | $Guests = $GuestsRaw -split ",$([regex]'[\s]*')"
3 |
4 | $Guests | ForEach-Object { Write-Output "Welcome, $PSItem!" }
--------------------------------------------------------------------------------
/ch07/05-Write-GuestSeatDetails.csv:
--------------------------------------------------------------------------------
1 | Name,Seat
2 | Mr Jain,A-12
3 | Mr Jacobs,C-28
4 | Ms Sanders,B-17
5 | Mr Shah,M-22
6 | Mr Hugo,E-08
--------------------------------------------------------------------------------
/ch07/05-Write-GuestSeatDetails.ps1:
--------------------------------------------------------------------------------
1 | $Guests = Import-Csv './ch07/05-Write-GuestSeatDetails.csv'
2 |
3 | foreach ($Guest in $Guests) {
4 | $RowIdentifier = [byte][char](($Guest.Seat -split '-')[0].ToUpper())
5 | # Split the seat identifier at '-' : $Guest.Seat -split '-'
6 | # Pick the first element from the resultant array : ($Guest.Seat -split '-')[0]
7 | # Enforce uppercase : ($Guest.Seat -split '-')[0].ToUpper()
8 | # Convert it to char : [char](($Guest.Seat -split '-')[0].ToUpper())
9 | # Find the ASCII identifier : [byte][char](($Guest.Seat -split '-')[0].ToUpper())
10 |
11 | $RowNumber = ($RowIdentifier - 64).ToString()
12 | # A should be 1, B should be 2, C should be 3...
13 |
14 | switch -Regex ($RowNumber) {
15 | '1(1|2|3)$' { $RowNumber += 'th'; break } # Generate 11th, 12th, 13th
16 | '.?1$' { $RowNumber += 'st'; break } # 1st, 21st
17 | '.?2$' { $RowNumber += 'nd'; break } # 2nd, 22nd
18 | '.?3$' { $RowNumber += 'rd'; break } # 3rd, 23rd
19 | Default { $RowNumber += 'th'; break } # everything else from 1 to 26 should have 'th'.
20 | }
21 |
22 | $SeatNumber = ($Guest.Seat -split "-")[1]
23 | # Pick the numeric element
24 |
25 | if ($SeatNumber -gt 20) {
26 | $Side = 'right'
27 | }
28 | else {
29 | $Side = 'left'
30 | }
31 |
32 | Start-Sleep -Seconds 1
33 | Write-Host "Welcome, $($Guest.Name)! " -NoNewline # Subexpression `$Guest.Name` to be computed first.
34 | Start-Sleep -Seconds 1
35 | Write-Host "Your seat is in the $RowNumber row, to the $Side the aisle."
36 | }
--------------------------------------------------------------------------------
/ch07/06-Write-GuestSeatDetails.ps1:
--------------------------------------------------------------------------------
1 | $Guests = Import-Csv './ch07/05-Write-GuestSeatDetails.csv'
2 |
3 | for ($CurrentGuest = 0; $CurrentGuest -lt $Guests.Length; $CurrentGuest++) {
4 | $Guest = $Guests[$CurrentGuest]
5 |
6 | $RowIdentifier = [byte][char](($Guest.Seat -split '-')[0].ToUpper())
7 | # Split the seat identifier at '-' : $Guest.Seat -split '-'
8 | # Pick the first element from the resultant array : ($Guest.Seat -split '-')[0]
9 | # Enforce uppercase : ($Guest.Seat -split '-')[0].ToUpper()
10 | # Convert it to char : [char](($Guest.Seat -split '-')[0].ToUpper())
11 | # Find the ASCII identifier : [byte][char](($Guest.Seat -split '-')[0].ToUpper())
12 |
13 | $RowNumber = ($RowIdentifier - 64).ToString()
14 | # A should be 1, B should be 2, C should be 3...
15 |
16 | switch -Regex ($RowNumber) {
17 | '1(1|2|3)$' { $RowNumber += 'th'; break } # Generate 11th, 12th, 13th
18 | '.?1$' { $RowNumber += 'st'; break } # 1st, 21st
19 | '.?2$' { $RowNumber += 'nd'; break } # 2nd, 22nd
20 | '.?3$' { $RowNumber += 'rd'; break } # 3rd, 23rd
21 | Default { $RowNumber += 'th'; break } # everything else from 1 to 26 should have 'th'.
22 | }
23 |
24 | $SeatNumber = ($Guest.Seat -split "-")[1]
25 | # Pick the numeric element
26 |
27 | if ($SeatNumber -gt 20) {
28 | $Side = 'right'
29 | }
30 | else {
31 | $Side = 'left'
32 | }
33 |
34 | Start-Sleep -Seconds 1
35 | Write-Host "Welcome, $($Guest.Name)! " -NoNewline # Subexpression `$Guest.Name` to be computed first.
36 | Start-Sleep -Seconds 1
37 | Write-Host "Your seat is in the $RowNumber row, to the $Side the aisle."
38 | }
--------------------------------------------------------------------------------
/ch07/07.1-Write-GuestSeatDetails.ps1:
--------------------------------------------------------------------------------
1 | $Guests = Import-Csv './ch07/05-Write-GuestSeatDetails.csv'
2 | $CurrentGuest = 0
3 |
4 | while ($CurrentGuest -lt $Guests.Length) {
5 | $Guest = $Guests[$CurrentGuest]
6 |
7 | $RowIdentifier = [byte][char](($Guest.Seat -split '-')[0].ToUpper())
8 | $RowNumber = ($RowIdentifier - 64).ToString()
9 |
10 | switch -Regex ($RowNumber) {
11 | '1(1|2|3)$' { $RowNumber += 'th'; break }
12 | '.?1$' { $RowNumber += 'st'; break }
13 | '.?2$' { $RowNumber += 'nd'; break }
14 | '.?3$' { $RowNumber += 'rd'; break }
15 | Default { $RowNumber += 'th'; break }
16 | }
17 |
18 | $SeatNumber = ($Guest.Seat -split "-")[1]
19 |
20 | if ($SeatNumber -gt 20) { $Side = 'right' }
21 | else { $Side = 'left' }
22 |
23 | Start-Sleep -Seconds 1
24 | Write-Host "Welcome, $($Guest.Name)! " -NoNewline
25 | Start-Sleep -Seconds 1
26 | Write-Host "Your seat is in the $RowNumber row, to the $Side the aisle."
27 |
28 | $CurrentGuest++
29 | }
--------------------------------------------------------------------------------
/ch07/07.2-Find-MothersDay.ps1:
--------------------------------------------------------------------------------
1 | $Year = Read-Host "Enter the year (YYYY) you would like to find Mothers’ Day for"
2 |
3 | $CurrentDay = Get-Date "01 May $Year"
4 |
5 | while ($CurrentDay.DayOfWeek -ne 'Sunday') {
6 | $CurrentDay = $CurrentDay.AddDays(1)
7 | }
8 | $MothersDay = $CurrentDay.AddDays(7)
9 |
10 | Write-Output "Mothers’ Day falls on $($MothersDay.ToLongDateString())."
--------------------------------------------------------------------------------
/ch07/08-Remove-EmptyDirectories.ps1:
--------------------------------------------------------------------------------
1 | $Iteration = 0
2 | do {
3 | $AllDirectories = (Get-ChildItem -Path $HOME/random -Recurse -Directory).FullName
4 | $EmptyDirectories = $AllDirectories | Where-Object {(Get-ChildItem $PSItem).Count -eq 0}
5 | $EmptyDirectories | Remove-Item
6 |
7 | Write-Output "Iteration $Iteration. Removed the following $($EmptyDirectories.Count) directories."
8 | $EmptyDirectories
9 | $Iteration++
10 | } while ($EmptyDirectories.Count -gt 0)
--------------------------------------------------------------------------------
/ch07/08-input-file.txt:
--------------------------------------------------------------------------------
1 | ./dir-01/dir-07/dir-09/dir-13
2 | ./dir-02/dir-05/dir-06
3 | ./dir-03/dir-08/dir-10
4 | ./dir-04/dir-11/dir-12/dir-14
5 | ./dir-04/dir-11/dir-12/dir-15
6 | ./dir-04/dir-11/dir-12/dir-16
7 | ./dir-04/dir-11/dir-12/dir-17
8 | ./dir-04/dir-11/dir-12/dir-18/dir-19
9 | ./dir-04/dir-11/dir-12/dir-18/dir-20
--------------------------------------------------------------------------------
/ch07/09-Remove-EmptyDirectories.ps1:
--------------------------------------------------------------------------------
1 | $Iteration = 0
2 | do {
3 | $AllDirectories = (Get-ChildItem -Path $HOME/random -Recurse -Directory).FullName
4 | $EmptyDirectories = $AllDirectories | Where-Object {(Get-ChildItem $PSItem).Count -eq 0}
5 | $EmptyDirectories | Remove-Item
6 | $Count = $EmptyDirectories.Count
7 |
8 | Write-Output "Iteration $Iteration`nRemoved the following $Count directories. '$Count = 0' is $($Count -eq 0)"
9 | $EmptyDirectories
10 | $Iteration++
11 | } until ($Count -eq 0)
--------------------------------------------------------------------------------
/ch08/01-Clear-LogFiles.ps1:
--------------------------------------------------------------------------------
1 | # Change this to match ./path/of/your/choice/ from the aforementioned scripts
2 | $LabPath = "$HOME/random"
3 |
4 | $Today = Get-Date
5 | $TotalFileSize = 0
6 |
7 | $FilesToDelete = Get-ChildItem $LabPath -Recurse -File | Where-Object {[math]::Floor(($Today - $_.LastWriteTime).TotalDays) -eq 30}
8 |
9 |
10 | Write-Host "The following files will be deleted:"
11 | Write-Host $FilesToDelete.FullName
12 |
13 | foreach ($File in $FilesToDelete) {
14 | $TotalFileSize += $File.Length
15 | Remove-Item -Path $File -WhatIf
16 | }
17 |
18 | Write-Host "Total space cleared: $([math]::Round($TotalFileSize/[math]::Pow(1024, 2))) MB"
19 |
--------------------------------------------------------------------------------
/ch08/01-Set-LastWriteTime.ps1:
--------------------------------------------------------------------------------
1 | function Set-LastWriteTime {
2 | param (
3 | # Path to the random directory
4 | [Parameter(Mandatory=$false)]
5 | [string]
6 | $Path=(Join-Path $HOME -ChildPath random)
7 | )
8 | begin {
9 | $DateToSet = (Get-Date).AddDays(-25)
10 | $Files = Get-ChildItem -Path $Path -Recurse -File
11 | $NewerFiles = $Files | Select-Object -First 12
12 | $OlderFiles = $Files | Select-Object -Last 12
13 | }
14 | process {
15 | foreach ($File in $NewerFiles) {
16 | (Get-Item $File).LastWriteTime = $DateToSet
17 | }
18 | $DateToSet = $DateToSet.AddDays(-5)
19 | foreach ($File in $OlderFiles) {
20 | (Get-Item $File).LastWriteTime = $DateToSet
21 | }
22 | }
23 | }
24 | Set-LastWriteTime
--------------------------------------------------------------------------------
/ch08/02-Clear-LogFiles.ps1:
--------------------------------------------------------------------------------
1 | # Change this to match ./path/of/your/choice/ from the aforementioned scripts
2 | $LabPath = "$HOME/random"
3 |
4 | $Today = Get-Date
5 | $TotalFileSize = 0
6 |
7 | $AllFiles = Get-ChildItem $LabPath -Recurse -File
8 | $FilesToDelete = $AllFiles | Where-Object {[math]::Floor(($Today - $_.LastWriteTime).TotalDays) -eq 30}
9 |
10 |
11 | Write-Host "The following files will be deleted:"
12 | Write-Host $FilesToDelete.FullName
13 |
14 | foreach ($File in $FilesToDelete) {
15 | $TotalFileSize += $File.Length
16 | Remove-Item -Path $File -WhatIf
17 | }
18 |
19 | New-Object -TypeName psobject -Property @{
20 | TotalFiles = $AllFiles.Count
21 | FilesToDelete = $FilesToDelete.Count
22 | SpaceCleared = $TotalFileSize
23 | }
--------------------------------------------------------------------------------
/ch08/05-ConvertTo-Rgb.ps1:
--------------------------------------------------------------------------------
1 | $Rgb = Read-Host "Enter the hexadecimal RGB value"
2 | $TrimmedRgb = $Rgb.Substring($Rgb.Length - 6)
3 |
4 | $R = $TrimmedRgb.Substring(0, 2)
5 | $G = $TrimmedRgb.Substring(2, 2)
6 | $B = $TrimmedRgb.Substring(4, 2)
7 |
8 | "Here are the R, G and B levels for the supplied hex value:"
9 | $R, $G, $B | ForEach-Object { [int]("0x" + $PSItem) }
--------------------------------------------------------------------------------
/ch08/06-ConvertTo-OtherBases.ps1:
--------------------------------------------------------------------------------
1 | $InputString = Read-Host "Enter an integer"
2 |
3 | Write-Host "Octal representation: " -NoNewline
4 | [Convert]::ToString($InputString, 8)
5 |
6 | Write-Host "Hexadecimal representation: " -NoNewline
7 | [Convert]::ToString($InputString, 16)
8 |
9 | Write-Host "Binary representation: " -NoNewline
10 | [Convert]::ToString($InputString, 2)
--------------------------------------------------------------------------------
/ch09/01-New-MultiDimensionalArray.ps1:
--------------------------------------------------------------------------------
1 | $MultiDimensionalArray = New-Object -TypeName "int[,]" 4, 5
2 | $Count = 1
3 |
4 | for ([int]$i = 0; $i -lt 4; $i++) {
5 | for ([int]$j = 0; $j -lt 5; $j++) {
6 | $MultiDimensionalArray[$i,$j] = $Count
7 | $Count++
8 | }
9 | }
--------------------------------------------------------------------------------
/ch09/02-Convert-Name.ps1:
--------------------------------------------------------------------------------
1 | $Names = Get-Content .\ch09\02-names.txt
2 | $NewNames = @()
3 |
4 | foreach ($Name in $Names) {
5 | $Name = $Name -split ' '
6 | $NewName = $Name[1], $Name[0] -join ', '
7 |
8 | $NewNames += $NewName
9 | }
10 | $NewNames
--------------------------------------------------------------------------------
/ch09/02-names.txt:
--------------------------------------------------------------------------------
1 | Lila Day
2 | Wade Reed
3 | Kenny Todd
4 | Cindy Goodman
5 | Rick Howell
6 | Amber Mclaughlin
7 | Bernice Flowers
8 | Boyd Stanley
9 | Claire Greene
10 | Woodrow Mcdaniel
11 | Marcus Ward
12 | Colleen Roberts
13 | Brian Walton
14 | Grant Tyler
15 | Kara Leonard
16 | Dave Chapman
17 | Dwayne Pena
18 | Isaac Schultz
19 | Jacqueline Duncan
20 | Rudy Townsend
21 | Wilbert Gutierrez
22 | Wilma Hudson
23 | Geraldine James
24 | Diana Henderson
25 | Rosalie Terry
26 | Ellis Willis
27 | Bonnie Craig
28 | Alejandro Coleman
29 | Lorene Cohen
30 | Rex Summers
31 | Elvira Bell
32 | Rodney Drake
33 | Byron Washington
34 | Olga Bowen
35 | Steven Gonzalez
36 | Allen Barton
37 | Ignacio Lowe
38 | Billy Carroll
39 | Jeremy Erickson
40 | Owen Wade
41 | Karla Hunter
42 | Linda Bush
43 | Ervin Berry
44 | Laverne Gray
45 | Mack Turner
46 | Jaime Lawrence
47 | Zachary Massey
48 | Rosie Gilbert
49 | Frederick Blair
50 | Alfred Marshall
51 | Gary Matthews
52 | Johnnie Knight
53 | David Jenkins
54 | Willis Reyes
55 | Regina Edwards
56 | Dexter Santos
57 | Felix Miles
58 | Rachael Cummings
59 | Terry Smith
60 | Julie Sharp
61 | Maggie Hardy
62 | Jack Fuller
63 | Cameron Pearson
64 | Henry Baker
65 | Bryan Vega
66 | Leon Torres
67 | Darlene Conner
68 | Dana Davidson
69 | Steve Gibson
70 | Connie Shaw
71 | Jerry Chambers
72 | Kim Mills
73 | Bertha Burton
74 | Fernando Clayton
75 | Tony Greer
76 | Benny Roberson
77 | Nina Hawkins
78 | Francis Scott
79 | Hattie Grant
80 | Miranda Rodgers
81 | Malcolm Mack
82 | Susie Collins
83 | Verna Porter
84 | Jo Mcbride
85 | Ralph Cook
86 | Gwen Reynolds
87 | Lewis Francis
88 | Carol Mccoy
89 | Ismael Lucas
90 | Edwin Bowman
91 | Manuel Valdez
92 | Hope Guzman
93 | Shannon Nash
94 | Jenna Benson
95 | Timothy Rhodes
96 | Leland Figueroa
97 | Tyler Becker
98 | Tanya Mccarthy
99 | Clifton Gardner
100 | Gail Parks
--------------------------------------------------------------------------------
/ch09/03-Convert-SortedNames.ps1:
--------------------------------------------------------------------------------
1 | $Names = Get-Content .\ch09\02-names.txt | Sort-Object
2 | $NewNames = @()
3 |
4 | foreach ($Name in $Names) {
5 | $Name = $Name -split ' '
6 | $NewName = $Name[1], $Name[0] -join ', '
7 |
8 | $NewNames += $NewName
9 | }
10 | $NewNames
--------------------------------------------------------------------------------
/ch09/04-Find-Name.ps1:
--------------------------------------------------------------------------------
1 | $Names = Get-Content .\ch09\02-names.txt
2 | $NewNames = @()
3 |
4 | foreach ($Name in $Names) {
5 | $Name = $Name -split ' '
6 | $NewName = $Name[1], $Name[0] -join ', '
7 |
8 | $NewNames += $NewName
9 | }
10 | if ($NewNames -contains 'Torres,*') {
11 | Write-Host "Found Leon Torres in the list!"
12 | }
--------------------------------------------------------------------------------
/ch09/05-Combine-Arrays.ps1:
--------------------------------------------------------------------------------
1 | $ListOne = Get-Content ./05-list-one.txt
2 | $ListTwo = Get-Content ./05-list-two.txt
3 |
4 | "List one contains $($ListOne.Count) items."
5 | "List two contains $($ListTwo.Count) items."
6 |
7 | $CombinedList = $ListOne + $ListTwo
8 |
9 | $CombinedList
--------------------------------------------------------------------------------
/ch09/05-list-one.txt:
--------------------------------------------------------------------------------
1 | Wilbert Gutierrez
2 | Wilma Hudson
3 | Geraldine James
4 | Diana Henderson
5 | Rosalie Terry
6 | Ellis Willis
7 | Bonnie Craig
8 | Alejandro Coleman
9 | Lorene Cohen
10 | Rex Summers
--------------------------------------------------------------------------------
/ch09/05-list-two.txt:
--------------------------------------------------------------------------------
1 | Jerry Chambers
2 | Kim Mills
3 | Bertha Burton
4 | Fernando Clayton
5 | Tony Greer
6 | Benny Roberson
7 | Nina Hawkins
8 | Francis Scott
9 | Hattie Grant
10 | Miranda Rodgers
--------------------------------------------------------------------------------
/ch09/06-Search-ByLastname01.ps1:
--------------------------------------------------------------------------------
1 | $Names = Get-Content .\ch09\02-names.txt
2 | $Names = $Names -match 'son$'
3 |
4 | # or $Names = $Names -like '*son'
5 |
6 | $NewNames = @()
7 |
8 | foreach ($Name in $Names) {
9 | $Name = $Name -split ' '
10 | $NewName = $Name[1], $Name[0] -join ', '
11 |
12 | $NewNames += $NewName
13 | }
14 | $NewNames
--------------------------------------------------------------------------------
/ch09/06-Search-ByLastname02.ps1:
--------------------------------------------------------------------------------
1 | $Names = Get-Content .\ch09\02-names.txt
2 | $NewNames = @()
3 |
4 | foreach ($Name in $Names) {
5 | $Name = $Name -split ' '
6 | $NewName = $Name[1], $Name[0] -join ', '
7 |
8 | $NewNames += $NewName
9 | }
10 | "Using the match operator:"
11 | $NewNames -match 'son,'
12 |
13 | "Using the like operator:"
14 | $NewNames -like '*son,*'
--------------------------------------------------------------------------------
/ch09/07-Clear-Paths01.ps1:
--------------------------------------------------------------------------------
1 | $Paths = (Get-ChildItem $HOME/random -Recurse).FullName
2 | $Paths = $Paths | Where-Object {$PSItem -notmatch "^$HOME/random/dir-04"}
3 | Write-Output "Here is the list of paths within the lab directory, without those within dir-04:`n`n"
4 | $Paths
--------------------------------------------------------------------------------
/ch09/07-Clear-Paths02.ps1:
--------------------------------------------------------------------------------
1 | $AllPaths = New-Object -TypeName System.Collections.ArrayList
2 | foreach ($Path in (Get-ChildItem $HOME/random -Recurse)) {
3 | [void]$AllPaths.Add($Path.FullName)
4 | }
5 |
6 | $PathsToExclude = $AllPaths -match "^$HOME/random/dir-04"
7 |
8 | foreach ($Dir4Path in $PathsToExclude) {
9 | $AllPaths.Remove($Dir4Path)
10 | }
11 |
12 | Write-Output "Here is the list of paths within the lab directory, without those within dir-04:`n`n"
13 | $AllPaths
--------------------------------------------------------------------------------
/ch09/08-Compare-ServerName.ps1:
--------------------------------------------------------------------------------
1 | $MyServers = Get-Content ./ch09/08-server-names-01.txt
2 | $ModServers = Get-Content ./ch09/08-server-names-02.txt
3 |
4 | Compare-Object -ReferenceObject $MyServers -DifferenceObject $ModServers
--------------------------------------------------------------------------------
/ch09/08-server-names-01.txt:
--------------------------------------------------------------------------------
1 | undida
2 | hisomi
3 | staura
4 | kemers
5 | iaterv
6 | bysher
7 | kisthm
8 | indaho
9 | ecoena
10 | bolais
11 | arsure
12 | droerb
13 | uphawa
14 | anight
15 | quardi
16 | chlelo
17 | tichil
18 | aitapy
19 | zioldy
20 | dublan
21 | teanco
22 | dirlec
23 | aoradu
24 | spouir
25 | usealu
26 | honclu
27 | ounort
28 | odesco
29 | piteif
30 | onicia
--------------------------------------------------------------------------------
/ch09/08-server-names-02.txt:
--------------------------------------------------------------------------------
1 | undida
2 | hisomi
3 | staura
4 | heinap
5 | iaterv
6 | kisthm
7 | indaho
8 | ecoena
9 | bolais
10 | aptoor
11 | shaeco
12 | droerb
13 | modusp
14 | anight
15 | quardi
16 | hulont
17 | jublam
18 | urilip
19 | tichil
20 | aitapy
21 | exeini
22 | dublan
23 | teanco
24 | eullib
25 | spouir
26 | usealu
27 | ounort
28 | odesco
29 | piteif
30 | onicia
--------------------------------------------------------------------------------
/ch09/09-New-MemoryList.ps1:
--------------------------------------------------------------------------------
1 | $Processes = @{}
2 | Get-Process | ForEach-Object { $Processes[$PSItem.Name] = $PSItem.WS/1MB }
3 | $Processes['pwsh']
--------------------------------------------------------------------------------
/ch09/10-New-ProcessReport.ps1:
--------------------------------------------------------------------------------
1 | $Processes = @{}
2 | Get-Process | ForEach-Object { $Processes[$PSItem.Name] = $PSItem.WS/1MB }
3 |
4 | $Report = "The computer is currently running $($Processes.Count) processes."
5 |
6 | if ($Processes.Contains('pwsh') -or $Processes.Contains('pwsh-preview'
7 | )) {
8 | $Report += "`n`nPowerShell is also running at the moment."
9 | $Processes.Remove('pwsh')
10 | $Processes.Remove('pwsh-preview')
11 | }
12 | else {
13 | $Report += "`n`nPowerShell is not running at the moment."
14 | }
15 |
16 | $Report += "`n`nFollowing is the list of processes currently running, sorted by name:"
17 |
18 | $Report += "`n`n$(($Processes.GetEnumerator() | Sort-Object Name).Name -join "`n")"
19 |
20 | $Report += "`n`nThe average working set used is $(($Processes.Values | Measure-Object -Average).Average) MB. There are $($Processes.Count) processes running, apart from PowerShell."
21 |
22 | $Processes.Clear()
23 |
24 | $Report += "`n`n$($Processes.Count) processes left after clearing the list."
25 |
26 | $Report
--------------------------------------------------------------------------------
/ch10/01-Get-FileDetails.ps1:
--------------------------------------------------------------------------------
1 | Write-Host "File details:"
2 |
3 | Get-Item ./ch10/01-random-text.txt
4 |
5 | "Here are the first seven lines from the file."
6 |
7 | Get-Content ./ch10/01-random-text.txt -ReadCount 7 | Select-Object -First 1
8 |
9 | "Here are the last five lines from the file."
10 |
11 | Get-Content ./ch10/01-random-text.txt -Tail 5
12 |
13 | "Here are the eleventh to the thirteenth lines."
14 |
15 | Get-Content ./ch10/01-random-text.txt | Select-Object -First 3 -Skip 10
16 |
17 | "And here are some details about the content in the file."
18 |
19 | Get-Content ./ch10/01-random-text.txt | Measure-Object -Character -Word -Line
20 |
21 | "Finally, the content will be imported into a variable. Let us see if the content is a single block of text or not."
22 |
23 | $Content = Get-Content ./ch10/01-random-text.txt
24 |
25 | "There are $($Content.Count) elements in the variable."
26 |
27 | "When read as raw content, the number of elements is $((Get-Content ./ch10/01-random-text.txt -Raw).Count)"
--------------------------------------------------------------------------------
/ch10/01-random-text.txt:
--------------------------------------------------------------------------------
1 | qbpkSnAC NHwkZdgF kgVJhwRG OVWtNmSw xfHpbajI UAWBcfOq KpZtVzqJ AmoJRrIy
2 | GURaYbXl dlPtyzfZ dvjeSLHK GwkYQNcz qJfoWRuX UAeMozfE GVtLYMgu vUBZMuKR
3 | VUcXeSWH YDdwMPNn JBQHEAKk VlyKPdtR vpBUCZYO jZKbYUlV wsubJPBH wbitYrDO
4 | bNFIRxqU JhOdnmXP rbUghvFT yjDYdgzL knzPYjED opCYnMgb jZCGslaU XRrJOYtl
5 | CBqxivTy dgDJCvQx IWbBLRzM rJqoTkbt vpgrEJym qHVmhjbk NPghmZkq eoQkKLDB
6 | EpHWgoQG YbKwmEgL SIQRzOuf FyTQscpf HpGaIRTJ HNKakFTg JqSKeoRT uPgpJihO
7 | zyHCqNlV TczfsmhE ykKWgUJZ SeIavNli dfQbkoVy yStWCsTP oGUFAMPx TCYokKPe
8 | hxYsAcMU MPKmyHSI vWHMPfNO rTOJSFWd aPoNfJbu IxafOydt QXEpHBqo pjQxEKTk
9 | xAUHvoNK INDszMPW hjbupFKO gpDiRMJd YjUykXEN JsymwnGK bQFjslgr dykUieEI
10 | fNniqUxQ ObrfRWBJ abLkNzgh mPyqxXgk VsMWjNTA SLcDWsPr sSpaJfdI BYiPHscb
11 | yjPqdTxo VyRXWeah EMzgCFVf abFdzpXU RbYTqFAm aeUdnlty OVwMYjJT hwMzbsGX
12 | MWYBajuf lBaKjATO OURWsqeN OFEzZwsd QkZGlxrB URWtbXLD ybUXzxpW TdVFEsWK
13 | wZrOEaBL sEPBGNFw lIHBFuOW POiclsaN ZsUSuObo PjqVJrKX FyfWcPoK bzAHTmCK
14 | zpkyUlSE lWyVarkL ZGUMlJOQ fSMJCKLm WidjuVNG LiAjqElD hxKlOkUX GrhKjlcO
15 | GtqYfPJA bwkJKucG jcTZpGvC tblsqjZK wzDyknCj rbfvVCGX rlDEYqox vEAXkqxN
16 | XPEbGZgH bAGJMsax HVKaynYm xEVcBRGa SUBuLvXP gWvnDcIt bSrRusAT UAvYmWIg
17 | dLNxljYW yiRtzdZJ qxsidcCO MSEkclmH qPWNZejx RNsKgYoh pXsmlWfi EHozXvwO
18 | TPslkxjN pGVywuCM eugnTWBt dOwYemXo axwVIGZU mvuHjFqt bJTCPMDg qRwbMBNT
19 | IBQKpvYS PeEXcCdx xkXcZSUv UDsWnjzB BLbKQqwa lGUMqVfk OfLxEtDN BYXWyObE
20 | QhdbmgoX vxTRYMCA eoDLMYgF jVQDIfhA JRwToxnD rwYvMHZt OvbsWXya aecLRzuv
21 | UDOKAoRZ yauZDUkr QPFVdkDS mMCsZRUK ABecgFOf pivsnHwe NRKUahvj NZukAQyG
22 | IAUbOdsp asLezPqv OyKglaSA tnTLRjhk tuWSJirl OxFhteoU pbnzhutv pVtjFdPB
23 | cUCmyEXB OCNouBmz fBuVmykE fuHOarFx wSCIoRjX LnDOTZQS MjFLTkHW SGvZLhUF
24 | SaPUQAvI wcEyRIzq bhWexyXZ JfgPpMRK KQzcgnbS nPXUaVsl ipPIbVmJ wUlYHeGF
25 | aKleQVhZ WXRYmkON rzHJkVAt YxNuWUPm qNaYDytm tGZFcLeP PIOZfNkR ThgclvHP
26 | fZFlULdg ZyQIPlTv ClRbmodw VsnKpUQW SWAtnveR xtqLflsQ yHwCmQns zunMEsVG
27 | hqNGZVEk IKCLbRMQ XIfoZBMF BZGIxHSz WSTAYFmJ HzNfwWKu aTzORvmr bKLsqeUZ
28 | MAKhFszO HlBhKeFr bDoBhVqy lJjdVcHG zQegJLbk KasuIvix VgdfctGl BqlcLYbS
29 | luGCLoUA yvMimhcG vDQPzpeb LvqOZkdD yUDpoSZl BJOQXbIN AmvgiHYS yaBsoJqF
30 | ojLsUBSw OjsnLtfU OwQgoGZC GRVyOeiH TGLtxkJh HelCyENR jbZJUahO mOZPThFA
31 | pHFmrZXP cXDYxoIB myGxZOuk vkHQSjVy oanqFSel WdliLvMS ZrdHshtg bWwdSlgs
32 | eygmVkxL iAnZDfRN LvRBMEsw ewAPhnRb MZFuiOKD hLRkBKfY NxuvdnkU HwGaDjOF
33 | DZaqfklW ekinaxKL KsBPmhzA ixLYMKFy spEQIVAx rgkAevCZ QbJtlUhd GROeQZFn
34 | nGzwyPCN ULsQNbmS OhHQrJwN SJYRIZUi LpqXRlyA pidVxEUF YhtnakbE eoxKEDFZ
35 | oCATkiYS SvZBUsgp zZApLkTF whUqxzEX zmRLVyrG fwznvskM pSFzlaRD VskeKJYv
36 | RhfUWbiz PaLzGTpD SCcwkzpV qdBFSRKm OedSDmWv pzaTOwFl NnBeZSKy YwuyTASp
37 | FMzJUpsd vAyiRHGg ONPuSBiE TctzOgjL phQlxNXd amZlVNnC tEkjMClm cdQwZeHN
38 | dPmjuklT MdhBmWqA glNbVuxI QvtNiVGu IXKQoTOB XiLvqtfU BSCfRgLG XiercLFA
39 | UbDHVpGA ZnTeSKwp hDNiwJKf WiHRrMsI hopLICvH mhRsxIwg TgnmzWlU JuedolNT
40 | HXZKmtAu ZTGNnbrA pztExQXP FnGgTQOb EyHwFlft MSVjhRNG zNnPfHLA gfuSTaOP
41 | UnGtFyxz kRYcLsAF UFXMVNiW qFfMlQpS dkfESigp yDYGoHfU XjLrKHsa JSNprkoI
42 | qbecgEkI jbZMOVwo maGURXPt IMwtTZXU athZsQHv kwPWcqNY PTSuykmO smdcZBNl
43 | spCHkVWl fbLwrHMc WDuGZyTU wqnMyWVA IJLDNyVC AEcqbStQ hmCWflLR ACdqVyei
44 | auPKFpyS EdWpbvNa AtVwcoST BDkeGNJW IoFNzHvj ZOlauEQd MwVcsqCr DGnpwoEm
45 | RruUWYBV KIDZEARS tmGnlreb dHjTcUPV rEeUscPh sohfkzXR NtLTgkJj cBOwbxYe
46 | TgmhPSEZ BrnzhJPw tCmMsKfD YbFRzyoN pELrxPtB EelPhUJX LTZNzHrI SqwVzKWb
47 | iwqoOusz ABTQdeXZ JFpGWPzO gfkHJhuy zMhySEcY zwWjgnOr BwSFXhvd GIouJpfL
48 | iNxlvGmu vDopucVI MbgVSiNo UsvKlxLJ kWOKhYzA CGVwLvFK vQFgzsRi RncAPflj
49 | JdMKNjCa JkXbOifs rAUsOXdY pgqQLGyb nWKVcqIg BEtvyMiU TwGUkHYg ZazsMyjm
50 | KzIemHgf CibGkmPs txgozuYM cCmopxjT wxbSvtkl JBWouZsn NeQEYUbg XyKcMEYC
51 | kpgNwIRq PpoUWdRk AOIzJsoS qsAklxnM qnLOesvK BTeopWGH trQZudzx GMmvlyYu
52 | CkXfDoKc DcCiuKzr CuoUDrfp GfAFEdNo vYEHLbXu CHsSBRGk DTzFoLaE hvkfzFVg
53 | KbhpGeOP NQusyHUc VtdYbMHw Oixgosvf jdXntNLg rsuCHYLj AYbQLXWk BPtwUIgX
54 | ZqRGklNo QfIlUuSV aiCBQvzN oLxjDSbk JsWhicIP IjuaPsHK ftgpXJrT hilmyftw
55 | EGzyAlRa pUGXsxfJ RUiVepOB YjDEFOtC DrHbCSBl AoQEgLdT hXpsjnig IKhEraVO
56 | qWYuViNo SmepvEuh cLsWdzKm wSgZHijk KfUNARWG wQaUdYbK wVBJpjGn kOQNbBGE
57 | kVtFQEwD OZcGgPMQ PDwnAXjN sXJVnkti suBYUbCi fiEsZPwS BwRdYVQx NWfhlIUb
58 | vQjCgaUh eoXyzkIx fwuUhvPO oqHAkKuM qUCftxER MczWYOZL sqiwoTmr ZtynhJzW
59 | VZTrueyX mAuJwZOa HYqTSPve TRDzMrvK bkdhfcjQ vkugDEmR lJZmqNxV lnYduaft
60 | fXLCwrKU BGxvEYNS MtySBwRb xVzHLPoK eTMHBglf TMzUEplH sVQktMAC mresCvzq
61 | zvhZeitf lFUfIEPu uRoPqZGw iqSQhfTE EdnITrBZ uThMaNSD vhQabTle ihZJTeaH
62 | KEtVxIrN QSsFJDAU sSaEogHJ aeNbvPUC EoxUQTcW IbliTqCt TAIQJdRp giJxDNHp
63 | pKJfUSrE ersLjNoH KnVFrPEW cLnETsJW zABmoHkw FSxhcTlG QxcnOzsi PBDZgFhr
64 | YJFuMEyT EoxhDQGc skPpNqEB AhXmBfZL Hbftpzyq LEyPfDxe SKzTOWZP RwakAhtr
65 | BlAeGJcL jcAZIxGe lQxjqiGn OpXJnbCZ PSBfAsKN nKLXHwsc CpbfqKnm gpnlTNdL
66 | ExDPobCX fSnblKAU BPQrvlXF NTyJkZod tHKzvMuo BLHfsogY WFBAJHYe fjGtqZTw
67 | pEuICXZk LmcDqZzF zjZNVORl AGbLczOI esMXBLnt sAXCINpe lfTWNodP VjrIbcmQ
68 | YKUtgyZa gQkOwUdV CoPypSYH BRSNCqUL mFloIDMY PCZzUigJ cWTuhBAb KwVyFZND
69 | DsUFISOR EWVBiZJz cmPsRuez ardXDNgz GOLMQquD dTIAQFuh ioTesDbm HnfAKvGx
70 | HKRlijGZ wvGmkYKl qSfxaVTw HGeyUEoj ZISnARjY zfSbuprY aSEpNOtQ drmMOFJQ
71 | VtPcnmGg embtOjNJ EAeWGLRZ ZWGqTXxc hGvwpsZS FmoWOZzG YwtCGjBR swYOlfEM
72 | VHzUjceI sMOJvFrh gsuvbNWY iwNAIBQV kAuBVIPa WoNgaAzc Druacbhs ihKtHNDe
73 | jqfoDGMz cBoRuSwm IYqPdlZS abyAOgnF QSsdGyze cLgfReZk bJHuYsPR FPoOfUQY
74 | bOdTsBIX vnIGmCZP JoipnhRu JzkbheKU rRYNnSdQ UtzejPvB MBdQefVI PLESktcC
75 | vbPaOGYo TWjUqsoX ovlCpOrD cVIjkUmg BtKRXhjv rAOxkNGb gWUQqPKb uhSQlfwp
76 | HuLbOdzM AJxosFyr mwvltjVU MZTDCgHl AWvxZCMu SlLCGbcJ rAxPpFIU CLoVPsbe
77 | HMLSdtzi gqEiOmyG pBajfPkr fRMtUeVP SQomnUvw FEGnytVg kjldcoAe DlLMxGsy
78 | GATmESco bndwopkT osDMpCmw bMyQDFSz WmdRnsrP VRQpXqvc CwgTrQXY EwNgAicU
79 | OLGnpwbq afIRymtd ejVRBHhF yhmecqHp LztfgBbU hcUlLfYn OqKvaRmA oUzgIurm
80 | ZsmTXISy GNqBtaxi xfgJQwdz DFwdlhCV LdctjqUk BWhmdpDk EGfHVMiP KuVzPOYC
81 | gsWLNUtd xaFdqpDe dUCHcSQJ AjQNpIGT ufPFDVzS EuPtFBjZ XwCKvqUb EJOjtlZd
82 | HivVJqYn wRTmEDou YGaTNUVk WTfIvVLZ ADjXhlec CvwhMTPB DRBivmpy aTQIMxnA
83 | wjgvlFyc zpnKPgoa qRudeFAB CjydORuv TbwKegsu LoNthVdE qjBQPIad ahuncRVl
84 | YDzqVClQ pUnuIMlF goJFzHqV bjHKrTXA KCjZpcMY KNdrBcGe xVpgoOWa cTjFzRCn
85 | wKvCukpS yxtdnKQD tqxenUSX hEfXsiWN tIEDqnNR SoTkKIrB cIxNnSLj RWptzMZf
86 | RnExHQTw NfDhpyos podiALmZ zWtxkFUh RJcXaOko wBAcHLzU tSkhCQUZ pJqHsviD
87 | HhVDQlWF PbHTtRVu fEDVJZRc xswICYQD rsRtQvAz zdNQfuEA CrWxivuS igVFEdJy
88 | wiFmyDdK woLfKNaq DxlCWoKt zvybecMA mIsDzhBQ eIinYGow HMJCFQqf VTFrLbtj
89 | rqGvDATp qPUndizH TGNfvCKk lNQmhSVe byfqVnwc UFhDegZE DoLFVAbw FJQRGXaW
90 | JwLZzXoO jAWSRvOI YJEUmsSF ERcYJATp MokXPmpr XRYyOuPC JvRfOqka TKABCqgd
91 | RHPIlEku QzsYketZ tfiWTSUb AfNwdDhy icTmDxaX dRopNALy gXzsOlGJ KvytzbBT
92 | bpfdDwKe knalNirQ tFmRhUvP ZrewqyPV NzSIeKCJ ZEnXsOqI qBnOjozt JDIoLQyw
93 | pwJWCAeB RZDpgXMS jdORXoJL PkylEnMm nwhNKmCe DqjbrkCS FVOekauX OkFCwdfq
94 | xKCycRtL PXaxfDKE aDgJuhvR LwrXiAgN uvSXVOYn JEsuWObp OJbFcXLW KOzsVTSl
95 | bgSfEMYK tJIhDivU lguoYkip hbqiAlMT uajXODUh vdVPnhLp RiAaUskC jxBzJrki
96 | VFgXIzQk HZGcDMYt gqFbPACU mHgGxjAM LUgGKXSc smbtPYRU elihSvrV BRCYdXyb
97 | qcngRWZe chIiuCQo NXhAQyrx szJVCWXY HMQAScil PDRNUzcx jzndkBvP dvxZsRcw
98 | AYpoKzNL HagEtTAJ SAsxhlpo MSwtNxfl bcJlNAma YpstwNmA SnkTNPtj EcMdRqHP
99 | NOSYnKmA DOnNEsvT HpMOIZUC iZYslRFp RUovKZcO MUQrocqB AVtWeExD wzvXEmji
100 | rdDEfyOA OHVJXDCw knIaeuWT OsinbJXm vYxZOJTu riATSBJm sWUIjVXY PWEysKwq
--------------------------------------------------------------------------------
/ch10/02-Write-ContentOne.ps1:
--------------------------------------------------------------------------------
1 | Get-ChildItem $HOME/random/dir-04 > $HOME/random/file-list.txt
2 |
3 | Get-ChildItem $HOME/random/dir-05 > $HOME/random/error.txt
4 |
5 | Write-Host "Listing the contents of ~/random/dir-03 and appending the list to file-list.txt." > $HOME/random/message.txt
6 |
7 | Get-ChildItem $HOME/random/dir-03 | Tee-Object $HOME/random/file-list.txt -Append
--------------------------------------------------------------------------------
/ch10/02-Write-ContentTwo.ps1:
--------------------------------------------------------------------------------
1 | Get-ChildItem $HOME/random/dir-04 | Out-File $HOME/random/file-list.txt
2 |
3 | Get-ChildItem $HOME/random/dir-05 2>&1 | Out-File $HOME/random/error.txt
4 |
5 | Write-Host "Listing the contents of ~/random/dir-03 and appending the list to file-list.txt." 6>&1 | Out-File $HOME/random/message.txt
6 |
7 | Get-ChildItem $HOME/random/dir-03 | Tee-Object $HOME/random/file-list.txt -Append
8 |
9 | <# Alternatives, using only operators:
10 | Get-ChildItem $HOME/random/dir-04 > $HOME/random/file-list.txt
11 |
12 | Get-ChildItem $HOME/random/dir-05 2>&1 > $HOME/random/error.txt
13 |
14 | Write-Host "Listing the contents of ~/random/dir-03 and appending the list to file-list.txt." 6>&1 > $HOME/random/message.txt
15 |
16 | Get-ChildItem $HOME/random/dir-03 | Tee-Object $HOME/random/file-list.txt -Append
17 | #>
--------------------------------------------------------------------------------
/ch10/03-Modify-FileContent.ps1:
--------------------------------------------------------------------------------
1 | #region Copy files to a backup directory before proceeding:
2 | New-Item $HOME/random/backup/ -ItemType Directory
3 | Copy-Item $HOME/random/message.txt, $HOME/random/file-list.txt, $HOME/random/error.txt $HOME/random/backup/
4 |
5 | # Verbose version: Copy-Item -Path $HOME/random/message.txt, $HOME/random/file-list.txt, $HOME/random/error.txt -Destination $HOME/random/backup/
6 | #endregion
7 |
8 | #region Commence operations
9 | Set-Content $HOME/random/message.txt "Successfully sent the contents of ~/random/dir-03 and appending the list to file-list.txt"
10 |
11 | # Verbose version: Set-Content -Path $HOME/random/message.txt -Value "Successfully sent the contents of ~/random/dir-03 and appending the list to file-list.txt"
12 |
13 | Add-Content $HOME/random/message.txt, $HOME/random/file-list.txt (Get-Date)
14 |
15 | # Vervose version: Add-Content -Path $HOME/random/message.txt, $HOME/random/file-list.txt -Value (Get-Date)
16 |
17 | Clear-Content $HOME/random/error.txt
18 |
19 | # Verbose version: Clear-Content -Path $HOME/random/error.txt
20 | #endregion
21 |
22 | "Here are the contents before and after the modifications:"
23 |
24 | "Message (before):"
25 | Get-Content $HOME/random/backup/message.txt
26 |
27 | "Message (now):"
28 | Get-Content $HOME/random/message.txt
29 |
30 | Read-Host -Prompt "Press ENTER to continue"
31 |
32 | "File list (before):"
33 | Get-Content $HOME/random/backup/file-list.txt
34 |
35 | "File list (now):"
36 | Get-Content $HOME/random/file-list.txt
37 |
38 | Read-Host -Prompt "Press ENTER to continue"
39 |
40 | "Error (before):"
41 | Get-Content $HOME/random/backup/error.txt
42 |
43 | "Error (now):"
44 | Get-Content $HOME/random/error.txt
--------------------------------------------------------------------------------
/ch10/04-Search-FileForPattern.ps1:
--------------------------------------------------------------------------------
1 | $ReportPath = "$HOME/random/FileSearchReport.txt"
2 | $CheatsheetPath = "$HOME/Documents/code/github/powershell/cheatsheets"
3 |
4 | if (!(Test-Path $ReportPath)) {
5 | New-Item $ReportPath -ItemType File -Force
6 | }
7 |
8 | "Here are the PowerShell code blocks present within the cheatsheets." | Out-File $ReportPath
9 | Select-String '```powershell' $CheatsheetPath/*.md |
10 | ForEach-Object {
11 | $PSItem = $PSItem -split ':'
12 | Write-Output "File Name: $($PSItem[0])"
13 | Write-Output "Line number: $($PSItem[1])"
14 | Write-Output "Pattern: $($PSItem[2])`n"
15 | } | Out-File $ReportPath -Append
16 |
17 | <# Verbose version:
18 | Select-String -Pattern '```powershell' -Path $CheatsheetPath/*.md
19 | #>
20 |
21 | "Here is a contextual report of all the PowerShell code blocks:" | Out-File $ReportPath -Append
22 | Select-String '```powershell' $CheatsheetPath/*.md -Context 2, 2 |
23 | Select-Object Path, LineNumber, `
24 | @{ Name = "Before"; Expression = { $PsItem.Context.PreContext -join "`n" } }, `
25 | @{ Name = "After"; Expression = { $PsItem.Context.PostContext -join "`n" } } |
26 | Format-List | Out-File $ReportPath -Append
27 |
28 | "Here are the files that contain the word, 'command' in them, except the cheatsheet for the first chapter:" | Out-File $ReportPath -Append
29 | Select-String 'command' $CheatsheetPath/*.md -Exclude '*chapter-01.md' |
30 | Group-Object Path |
31 | Select-Object Name, Count |
32 | Format-Table -AutoSize | Out-File $ReportPath -Append
33 |
34 | "Here are the files that contain the word, 'PowerShell' in them." | Out-File $ReportPath -Append
35 | Select-String -CaseSensitive 'PowerShell' $CheatsheetPath/*.md -Exclude '*chapter-01.md' |
36 | Select-Object Path -Unique |
37 | Format-Table -AutoSize | Out-File $ReportPath -Append
--------------------------------------------------------------------------------
/ch10/05-Get-InvocationInformation.ps1:
--------------------------------------------------------------------------------
1 | "The script is located within:"
2 | $PSScriptRoot
3 |
4 | Read-Host "Press Enter to continue"
5 |
6 | "Here is the complete path to the script that was run:"
7 | $PSCommandPath
8 |
9 | Read-Host "Press Enter to continue"
10 |
11 | "Creating a new folder, demo-lab in the home directory, and adding files to it."
12 |
13 | $Path = Join-Path $HOME 'demo-lab'
14 | # Verbose: Join-Path -Path $HOME -ChildPath 'demo-lab'
15 |
16 | "Creating files at the demo lab location."
17 | New-Item $Path -ItemType Directory
18 |
19 | 'random-text.txt', 'himalayas.jpg', 'crunched-numbers.csv', 'screenshot-001.png', 'screenshot-002.png', 'screenshot-003.png', 'demo.doc', 'my-plugin.rb' | ForEach-Object { New-Item -Path (Join-Path -Path $Path -ChildPath $PSItem) -ItemType File }
--------------------------------------------------------------------------------
/ch10/06-New-FilesAndDirectories.ps1:
--------------------------------------------------------------------------------
1 | Set-Location (Join-Path $HOME random)
2 |
3 | Join-Path dir-01, dir-02, dir-03, dir-04 -ChildPath demo.txt | ForEach-Object { New-Item $PSItem -ItemType File }
4 |
5 | 'random-text.txt', 'himalayas.jpg', 'crunched-numbers.csv', 'screenshot-001.png', 'screenshot-002.png', 'screenshot-003.png', 'demo.doc', 'my-plugin.rb' | ForEach-Object { New-Item (Join-Path dir-01 -ChildPath $PSItem) -ItemType File }
6 |
7 | Rename-Item screenshot-001.png myscreenshot.png
8 | # Verbose version: Rename-Item -Path screenshot-001.png -NewName myscreenshot.png
9 |
10 | Copy-Item myscreenshot.png dir-02
11 | # Verbose version: Copy-Item -Path myscreenshot.png -Destination ./dir-02
12 |
13 | Remove-Item dir-04 -Recurse
14 | # Verbose version: Remove-Item -Path ./dir-04 -Recurse
--------------------------------------------------------------------------------
/ch10/07-Get-FilteredFiles.ps1:
--------------------------------------------------------------------------------
1 | $ThresholdDate = (Get-Date).AddDays(-7)
2 |
3 | Get-ChildItem $HOME/random -rec -na *.mp4 | Where-Object { $_.CreationTime -lt $ThresholdDate -and $_.Length -gt 100KB }
4 |
5 | # Verbose version: Get-ChildItem $HOME/random -Recurse -Name *.mp4 | Where-Object -FilterScript { $PSItem.CreationTime -lt $ThresholdDate -and $PSItem.Length -gt 100KB }
6 |
7 | Get-ChildItem $HOME/random -Recurse | Sort-Object Length -Descending | Select-Object -First 5
8 | # Verbose version: Get-ChildItem -Path $HOME/random -Recurse | Sort-Object -Property Length -Descending | Select-Object -First 5
--------------------------------------------------------------------------------
/ch10/08-Read-MdmLog.ps1:
--------------------------------------------------------------------------------
1 | $AllLogLines = Get-Content ./ch10/08-mdm-reinstall-log.log
2 | $UserTable = @()
3 |
4 | foreach ($Line in $AllLogLines) {
5 | $Timestamp = ($Line.Split(' '))[0]
6 |
7 | $Line = $Line -replace ".+(DeviceActionEvent)\ \{", '{'
8 | $Line = $Line -replace '\]$'
9 |
10 | <# Alternatively:
11 | $Line = $Line | Select-String -Pattern '(\{.*})' |
12 | ForEach-Object {
13 | $PSItem.Matches | ForEach-Object {
14 | $PSItem.Value
15 | }
16 | }
17 | #>
18 |
19 | $JsonData = ConvertFrom-Json $Line
20 | $UserInfo = $JsonData.userDeviceInfo.userInfo
21 |
22 | $Record = [ordered]@{
23 | Timestamp = Get-Date $Timestamp -Format d
24 | Username = $UserInfo.userName
25 | EmailAddress = $UserInfo.emailAddress
26 | }
27 |
28 | $UserTable += New-Object -TypeName psobject -Property $Record
29 | }
30 | $UserTable = $UserTable | Sort-Object Username -Unique | Sort-Object Timestamp
31 | $UserTable
--------------------------------------------------------------------------------
/ch10/08-mdm-reinstall-log.log:
--------------------------------------------------------------------------------
1 | 2018-09-06T00:09:45.351-0500 - CORE Exchange[Body: DeviceActionEvent {"eventTypeId":"979dba5297b4c8c8a9fb59d25f33fd2a","timestamp":1536210585273,"tenantId":1,"tenantGuid":"5b73c758-57af-47b2-a6d4-d7b6c52cb5e5","externalTenantId":"S650643799","correlationId":"7876c65b-2ba4-7648-9a94-1ef6fb492c3b","hostName":"svrbbp.mydomain.com","version":"5.63.87-SNAPSHOT","severity":"CLEARED","tags":["device_action","user","userdevice"],"userDeviceInfo":{"enrollmentType":"MDM_CONTROLS","perimeterUuid":"afa57869b-3f76-7e74-98d8-ab725136a663","userInfo":{"userGuid":"af78905c-806f-49a8-b491-3f3fc26564e5","userName":"NBFA091","emailAddress":"Joyce.Rose@mydomain.com"},"deviceInfo":{"deviceOSFamily":"ios","id":1332,"udid":"4a7783999478577b7746dc774657b992","guid":"6657bc4e-19d5-b4bc-b05c-2e3c63190a11"},"perimeterState":"ENROLLED"},"deviceActionType":"INSTALL_APP"}]
2 | 2018-09-06T04:22:49.394-0500 - CORE Exchange[Body: DeviceActionEvent {"eventTypeId":"979dba5297b4c8c8a9fb59d25f33fd2a","timestamp":1536225769347,"tenantId":1,"tenantGuid":"5b73c758-57af-47b2-a6d4-d7b6c52cb5e5","externalTenantId":"S650643799","correlationId":"7876c65b-2ba4-7648-9a94-24c74ac96804","hostName":"svrbbp.mydomain.com","version":"5.63.87-SNAPSHOT","severity":"CLEARED","tags":["device_action","user","userdevice"],"userDeviceInfo":{"enrollmentType":"MDM_CONTROLS","perimeterUuid":"afa57869b-1c6d-7e74-889a-2111504a181d","userInfo":{"userGuid":"af78905c-aad9-475e-b491-7287c31c00b5","userName":"NBPA581","emailAddress":"Al.Lindsey@mydomain.com"},"deviceInfo":{"deviceOSFamily":"ios","id":1196,"udid":"4a7783999478577b7746dc774657b992","guid":"6657bc4e-6af8-b4bc-a00a-3e4439d40662"},"perimeterState":"ENROLLED"},"deviceActionType":"INSTALL_APP"}]
3 | 2018-09-06T04:48:14.128-0500 - CORE Exchange[Body: DeviceActionEvent {"eventTypeId":"979dba5297b4c8c8a9fb59d25f33fd2a","timestamp":1536227294082,"tenantId":1,"tenantGuid":"5b73c758-57af-47b2-a6d4-d7b6c52cb5e5","externalTenantId":"S650643799","correlationId":"7876c65b-2ba4-7648-9a94-0debbac0e68e","hostName":"svrbbp.mydomain.com","version":"5.63.87-SNAPSHOT","severity":"CLEARED","tags":["device_action","user","userdevice"],"userDeviceInfo":{"enrollmentType":"MDM_CONTROLS","perimeterUuid":"afa57869b-8067-7e74-88fa-2573f3e735a5","userInfo":{"userGuid":"af78905c-efdb-4810-b491-880e0746b757","userName":"NBFA117","emailAddress":"Jody.Collins@mydomain.com"},"deviceInfo":{"deviceOSFamily":"ios","id":1397,"udid":"4a7783999478577b7746dc774657b992","guid":"6657bc4e-2844-b4bc-877b-5ea155afadd5"},"perimeterState":"ENROLLED"},"deviceActionType":"INSTALL_APP"}]
4 | 2018-09-06T05:00:51.368-0500 - CORE Exchange[Body: DeviceActionEvent {"eventTypeId":"979dba5297b4c8c8a9fb59d25f33fd2a","timestamp":1536228051337,"tenantId":1,"tenantGuid":"5b73c758-57af-47b2-a6d4-d7b6c52cb5e5","externalTenantId":"S650643799","correlationId":"7876c65b-2ba4-7648-9a94-73a6b6f825ec","hostName":"svrbbp.mydomain.com","version":"5.63.87-SNAPSHOT","severity":"CLEARED","tags":["device_action","user","userdevice"],"userDeviceInfo":{"enrollmentType":"MDM_CONTROLS","perimeterUuid":"afa57869b-1c6d-7e74-889a-2111504a181d","userInfo":{"userGuid":"af78905c-aad9-475e-b491-7287c31c00b5","userName":"NBPA581","emailAddress":"Al.Lindsey@mydomain.com"},"deviceInfo":{"deviceOSFamily":"ios","id":1196,"udid":"4a7783999478577b7746dc774657b992","guid":"6657bc4e-6af8-b4bc-a00a-3e4439d40662"},"perimeterState":"ENROLLED"},"deviceActionType":"INSTALL_APP"}]
5 | 2018-09-06T05:57:08.728-0500 - CORE Exchange[Body: DeviceActionEvent {"eventTypeId":"979dba5297b4c8c8a9fb59d25f33fd2a","timestamp":1536231428697,"tenantId":1,"tenantGuid":"5b73c758-57af-47b2-a6d4-d7b6c52cb5e5","externalTenantId":"S650643799","correlationId":"7876c65b-2ba4-7648-9a94-1c9ac25ad19b","hostName":"svrbbp.mydomain.com","version":"5.63.87-SNAPSHOT","severity":"CLEARED","tags":["device_action","user","userdevice"],"userDeviceInfo":{"enrollmentType":"MDM_CONTROLS","perimeterUuid":"afa57869b-8067-7e74-88fa-2573f3e735a5","userInfo":{"userGuid":"af78905c-efdb-4810-b491-880e0746b757","userName":"NBFA117","emailAddress":"Jody.Collins@mydomain.com"},"deviceInfo":{"deviceOSFamily":"ios","id":1397,"udid":"4a7783999478577b7746dc774657b992","guid":"6657bc4e-2844-b4bc-877b-5ea155afadd5"},"perimeterState":"ENROLLED"},"deviceActionType":"INSTALL_APP"}]
6 | 2018-09-06T06:11:34.245-0500 - CORE Exchange[Body: DeviceActionEvent {"eventTypeId":"979dba5297b4c8c8a9fb59d25f33fd2a","timestamp":1536232294183,"tenantId":1,"tenantGuid":"5b73c758-57af-47b2-a6d4-d7b6c52cb5e5","externalTenantId":"S650643799","correlationId":"7876c65b-2ba4-7648-9a94-c2bc24106d60","hostName":"svrbbp.mydomain.com","version":"5.63.87-SNAPSHOT","severity":"CLEARED","tags":["device_action","user","userdevice"],"userDeviceInfo":{"enrollmentType":"MDM_CONTROLS","perimeterUuid":"afa57869b-a8d8-7e74-98d7-a07c075a38bd","userInfo":{"userGuid":"af78905c-b049-4cf4-b491-d4b3bb81183c","userName":"NBOB376","emailAddress":"Jean.Blair@mydomain.com"},"deviceInfo":{"deviceOSFamily":"ios","id":1618,"udid":"4a7783999478577b7746dc774657b992","guid":"6657bc4e-fac9-b4bc-9a78-b81cf41f0633"},"perimeterState":"ENROLLED"},"deviceActionType":"INSTALL_APP"}]
7 | 2018-09-06T06:28:25.665-0500 - CORE Exchange[Body: DeviceActionEvent {"eventTypeId":"979dba5297b4c8c8a9fb59d25f33fd2a","timestamp":1536233305618,"tenantId":1,"tenantGuid":"5b73c758-57af-47b2-a6d4-d7b6c52cb5e5","externalTenantId":"S650643799","correlationId":"7876c65b-2ba4-7648-9a94-16100b4cd18a","hostName":"svrbbp.mydomain.com","version":"5.63.87-SNAPSHOT","severity":"CLEARED","tags":["device_action","user","userdevice"],"userDeviceInfo":{"enrollmentType":"MDM_CONTROLS","perimeterUuid":"afa57869b-1c6d-7e74-889a-2111504a181d","userInfo":{"userGuid":"af78905c-aad9-475e-b491-7287c31c00b5","userName":"NBPA581","emailAddress":"Al.Lindsey@mydomain.com"},"deviceInfo":{"deviceOSFamily":"ios","id":1196,"udid":"4a7783999478577b7746dc774657b992","guid":"6657bc4e-6af8-b4bc-a00a-3e4439d40662"},"perimeterState":"ENROLLED"},"deviceActionType":"INSTALL_APP"}]
8 | 2018-09-06T07:11:15.156-0500 - CORE Exchange[Body: DeviceActionEvent {"eventTypeId":"979dba5297b4c8c8a9fb59d25f33fd2a","timestamp":1536235875109,"tenantId":1,"tenantGuid":"5b73c758-57af-47b2-a6d4-d7b6c52cb5e5","externalTenantId":"S650643799","correlationId":"7876c65b-2ba4-7648-9a94-ced4b1096412","hostName":"svrbbp.mydomain.com","version":"5.63.87-SNAPSHOT","severity":"CLEARED","tags":["device_action","user","userdevice"],"userDeviceInfo":{"enrollmentType":"MDM_CONTROLS","perimeterUuid":"afa57869b-1c6d-7e74-889a-2111504a181d","userInfo":{"userGuid":"af78905c-aad9-475e-b491-7287c31c00b5","userName":"NBPA581","emailAddress":"Al.Lindsey@mydomain.com"},"deviceInfo":{"deviceOSFamily":"ios","id":1196,"udid":"4a7783999478577b7746dc774657b992","guid":"6657bc4e-6af8-b4bc-a00a-3e4439d40662"},"perimeterState":"ENROLLED"},"deviceActionType":"INSTALL_APP"}]
9 | 2018-09-06T07:33:39.693-0500 - CORE Exchange[Body: DeviceActionEvent {"eventTypeId":"979dba5297b4c8c8a9fb59d25f33fd2a","timestamp":1536237219584,"tenantId":1,"tenantGuid":"5b73c758-57af-47b2-a6d4-d7b6c52cb5e5","externalTenantId":"S650643799","correlationId":"7876c65b-2ba4-7648-9a94-46712ab46dfa","hostName":"svrbbp.mydomain.com","version":"5.63.87-SNAPSHOT","severity":"CLEARED","tags":["device_action","user","userdevice"],"userDeviceInfo":{"enrollmentType":"MDM_CONTROLS","perimeterUuid":"afa57869b-886a-7e74-a811-0730d2bb13c8","userInfo":{"userGuid":"af78905c-04df-4c0e-b491-6ea0ce6bed16","userName":"NBob003","emailAddress":"Marion.Cohen@mydomain.com"},"deviceInfo":{"deviceOSFamily":"ios","id":1254,"udid":"4a7783999478577b7746dc774657b992","guid":"6657bc4e-55c9-b4bc-9223-54723922a997"},"perimeterState":"ENROLLED"},"deviceActionType":"INSTALL_APP"}]
10 | 2018-09-06T07:38:31.621-0500 - CORE Exchange[Body: DeviceActionEvent {"eventTypeId":"979dba5297b4c8c8a9fb59d25f33fd2a","timestamp":1536237511589,"tenantId":1,"tenantGuid":"5b73c758-57af-47b2-a6d4-d7b6c52cb5e5","externalTenantId":"S650643799","correlationId":"7876c65b-2ba4-7648-9a94-fae891dae7e2","hostName":"svrbbp.mydomain.com","version":"5.63.87-SNAPSHOT","severity":"CLEARED","tags":["device_action","user","userdevice"],"userDeviceInfo":{"enrollmentType":"MDM_CONTROLS","perimeterUuid":"afa57869b-71d4-7e74-b87d-95c42e6edece","userInfo":{"userGuid":"af78905c-e729-49c5-b491-8b9f11c25055","userName":"NBpa562","emailAddress":"Ruby.Chapman@mydomain.com"},"deviceInfo":{"deviceOSFamily":"ios","id":1500,"udid":"4a7783999478577b7746dc774657b992","guid":"6657bc4e-da34-b4bc-8687-1b80cc81f5fb"},"perimeterState":"ENROLLED"},"deviceActionType":"INSTALL_APP"}]
11 | 2018-09-06T07:49:40.639-0500 - CORE Exchange[Body: DeviceActionEvent {"eventTypeId":"979dba5297b4c8c8a9fb59d25f33fd2a","timestamp":1536238180592,"tenantId":1,"tenantGuid":"5b73c758-57af-47b2-a6d4-d7b6c52cb5e5","externalTenantId":"S650643799","correlationId":"7876c65b-2ba4-7648-9a94-d4dee1d3b48a","hostName":"svrbbp.mydomain.com","version":"5.63.87-SNAPSHOT","severity":"CLEARED","tags":["device_action","user","userdevice"],"userDeviceInfo":{"enrollmentType":"MDM_CONTROLS","perimeterUuid":"afa57869b-8067-7e74-88fa-2573f3e735a5","userInfo":{"userGuid":"af78905c-efdb-4810-b491-880e0746b757","userName":"NBFA117","emailAddress":"Jody.Collins@mydomain.com"},"deviceInfo":{"deviceOSFamily":"ios","id":1397,"udid":"4a7783999478577b7746dc774657b992","guid":"6657bc4e-2844-b4bc-877b-5ea155afadd5"},"perimeterState":"ENROLLED"},"deviceActionType":"INSTALL_APP"}]
12 | 2018-09-06T08:38:41.618-0500 - CORE Exchange[Body: DeviceActionEvent {"eventTypeId":"979dba5297b4c8c8a9fb59d25f33fd2a","timestamp":1536241121524,"tenantId":1,"tenantGuid":"5b73c758-57af-47b2-a6d4-d7b6c52cb5e5","externalTenantId":"S650643799","correlationId":"7876c65b-2ba4-7648-9a94-c31243e536c3","hostName":"svrbbp.mydomain.com","version":"5.63.87-SNAPSHOT","severity":"CLEARED","tags":["device_action","user","userdevice"],"userDeviceInfo":{"enrollmentType":"MDM_CONTROLS","perimeterUuid":"afa57869b-71d4-7e74-b87d-95c42e6edece","userInfo":{"userGuid":"af78905c-e729-49c5-b491-8b9f11c25055","userName":"NBpa562","emailAddress":"Ruby.Chapman@mydomain.com"},"deviceInfo":{"deviceOSFamily":"ios","id":1500,"udid":"4a7783999478577b7746dc774657b992","guid":"6657bc4e-da34-b4bc-8687-1b80cc81f5fb"},"perimeterState":"ENROLLED"},"deviceActionType":"INSTALL_APP"}]
13 | 2018-09-06T09:10:02.513-0500 - CORE Exchange[Body: DeviceActionEvent {"eventTypeId":"979dba5297b4c8c8a9fb59d25f33fd2a","timestamp":1536243002466,"tenantId":1,"tenantGuid":"5b73c758-57af-47b2-a6d4-d7b6c52cb5e5","externalTenantId":"S650643799","correlationId":"7876c65b-2ba4-7648-9a94-7be244daa12a","hostName":"svrbbp.mydomain.com","version":"5.63.87-SNAPSHOT","severity":"CLEARED","tags":["device_action","user","userdevice"],"userDeviceInfo":{"enrollmentType":"MDM_CONTROLS","perimeterUuid":"afa57869b-1c6d-7e74-889a-2111504a181d","userInfo":{"userGuid":"af78905c-aad9-475e-b491-7287c31c00b5","userName":"NBPA581","emailAddress":"Al.Lindsey@mydomain.com"},"deviceInfo":{"deviceOSFamily":"ios","id":1196,"udid":"4a7783999478577b7746dc774657b992","guid":"6657bc4e-6af8-b4bc-a00a-3e4439d40662"},"perimeterState":"ENROLLED"},"deviceActionType":"INSTALL_APP"}]
14 | 2018-09-06T09:49:02.366-0500 - CORE Exchange[Body: DeviceActionEvent {"eventTypeId":"979dba5297b4c8c8a9fb59d25f33fd2a","timestamp":1536245342319,"tenantId":1,"tenantGuid":"5b73c758-57af-47b2-a6d4-d7b6c52cb5e5","externalTenantId":"S650643799","correlationId":"7876c65b-2ba4-7648-9a94-fa85f40bab90","hostName":"svrbbp.mydomain.com","version":"5.63.87-SNAPSHOT","severity":"CLEARED","tags":["device_action","user","userdevice"],"userDeviceInfo":{"enrollmentType":"MDM_CONTROLS","perimeterUuid":"afa57869b-8067-7e74-88fa-2573f3e735a5","userInfo":{"userGuid":"af78905c-efdb-4810-b491-880e0746b757","userName":"NBFA117","emailAddress":"Jody.Collins@mydomain.com"},"deviceInfo":{"deviceOSFamily":"ios","id":1397,"udid":"4a7783999478577b7746dc774657b992","guid":"6657bc4e-2844-b4bc-877b-5ea155afadd5"},"perimeterState":"ENROLLED"},"deviceActionType":"INSTALL_APP"}]
15 | 2018-09-06T11:00:47.174-0500 - CORE Exchange[Body: DeviceActionEvent {"eventTypeId":"979dba5297b4c8c8a9fb59d25f33fd2a","timestamp":1536249647127,"tenantId":1,"tenantGuid":"5b73c758-57af-47b2-a6d4-d7b6c52cb5e5","externalTenantId":"S650643799","correlationId":"7876c65b-2ba4-7648-9a94-a5001569c5f0","hostName":"svrbbp.mydomain.com","version":"5.63.87-SNAPSHOT","severity":"CLEARED","tags":["device_action","user","userdevice"],"userDeviceInfo":{"enrollmentType":"MDM_CONTROLS","perimeterUuid":"afa57869b-fe35-7e74-a823-2635d591079a","userInfo":{"userGuid":"af78905c-f687-42fd-b491-fe2791e42a40","userName":"NBob106","emailAddress":"Essie.Douglas@mydomain.com"},"deviceInfo":{"deviceOSFamily":"ios","id":1436,"udid":"4a7783999478577b7746dc774657b992","guid":"6657bc4e-eae0-b4bc-be57-abefee274bee"},"perimeterState":"ENROLLED"},"deviceActionType":"INSTALL_APP"}]
16 | 2018-09-06T11:02:26.613-0500 - CORE Exchange[Body: DeviceActionEvent {"eventTypeId":"979dba5297b4c8c8a9fb59d25f33fd2a","timestamp":1536249746582,"tenantId":1,"tenantGuid":"5b73c758-57af-47b2-a6d4-d7b6c52cb5e5","externalTenantId":"S650643799","correlationId":"7876c65b-2ba4-7648-9a94-da3d688a5bbe","hostName":"svrbbp.mydomain.com","version":"5.63.87-SNAPSHOT","severity":"CLEARED","tags":["device_action","user","userdevice"],"userDeviceInfo":{"enrollmentType":"MDM_CONTROLS","perimeterUuid":"afa57869b-1c6d-7e74-889a-2111504a181d","userInfo":{"userGuid":"af78905c-aad9-475e-b491-7287c31c00b5","userName":"NBPA581","emailAddress":"Al.Lindsey@mydomain.com"},"deviceInfo":{"deviceOSFamily":"ios","id":1196,"udid":"4a7783999478577b7746dc774657b992","guid":"6657bc4e-6af8-b4bc-a00a-3e4439d40662"},"perimeterState":"ENROLLED"},"deviceActionType":"INSTALL_APP"}]
17 | 2018-09-06T12:20:28.084-0500 - CORE Exchange[Body: DeviceActionEvent {"eventTypeId":"979dba5297b4c8c8a9fb59d25f33fd2a","timestamp":1536254428037,"tenantId":1,"tenantGuid":"5b73c758-57af-47b2-a6d4-d7b6c52cb5e5","externalTenantId":"S650643799","correlationId":"7876c65b-2ba4-7648-9a94-248cf993a722","hostName":"svrbbp.mydomain.com","version":"5.63.87-SNAPSHOT","severity":"CLEARED","tags":["device_action","user","userdevice"],"userDeviceInfo":{"enrollmentType":"MDM_CONTROLS","perimeterUuid":"afa57869b-1c6d-7e74-889a-2111504a181d","userInfo":{"userGuid":"af78905c-aad9-475e-b491-7287c31c00b5","userName":"NBPA581","emailAddress":"Al.Lindsey@mydomain.com"},"deviceInfo":{"deviceOSFamily":"ios","id":1196,"udid":"4a7783999478577b7746dc774657b992","guid":"6657bc4e-6af8-b4bc-a00a-3e4439d40662"},"perimeterState":"ENROLLED"},"deviceActionType":"INSTALL_APP"}]
18 | 2018-09-06T12:40:26.220-0500 - CORE Exchange[Body: DeviceActionEvent {"eventTypeId":"979dba5297b4c8c8a9fb59d25f33fd2a","timestamp":1536255626173,"tenantId":1,"tenantGuid":"5b73c758-57af-47b2-a6d4-d7b6c52cb5e5","externalTenantId":"S650643799","correlationId":"7876c65b-2ba4-7648-9a94-c2ced769a120","hostName":"svrbbp.mydomain.com","version":"5.63.87-SNAPSHOT","severity":"CLEARED","tags":["device_action","user","userdevice"],"userDeviceInfo":{"enrollmentType":"MDM_CONTROLS","perimeterUuid":"afa57869b-71d4-7e74-b87d-95c42e6edece","userInfo":{"userGuid":"af78905c-e729-49c5-b491-8b9f11c25055","userName":"NBpa562","emailAddress":"Ruby.Chapman@mydomain.com"},"deviceInfo":{"deviceOSFamily":"ios","id":1500,"udid":"4a7783999478577b7746dc774657b992","guid":"6657bc4e-da34-b4bc-8687-1b80cc81f5fb"},"perimeterState":"ENROLLED"},"deviceActionType":"INSTALL_APP"}]
19 | 2018-09-06T13:24:53.042-0500 - CORE Exchange[Body: DeviceActionEvent {"eventTypeId":"979dba5297b4c8c8a9fb59d25f33fd2a","timestamp":1536258292980,"tenantId":1,"tenantGuid":"5b73c758-57af-47b2-a6d4-d7b6c52cb5e5","externalTenantId":"S650643799","correlationId":"7876c65b-2ba4-7648-9a94-670f97b54b1f","hostName":"svrbbp.mydomain.com","version":"5.63.87-SNAPSHOT","severity":"CLEARED","tags":["device_action","user","userdevice"],"userDeviceInfo":{"enrollmentType":"MDM_CONTROLS","perimeterUuid":"afa57869b-a8d8-7e74-98d7-a07c075a38bd","userInfo":{"userGuid":"af78905c-b049-4cf4-b491-d4b3bb81183c","userName":"NBOB376","emailAddress":"Jean.Blair@mydomain.com"},"deviceInfo":{"deviceOSFamily":"ios","id":1618,"udid":"4a7783999478577b7746dc774657b992","guid":"6657bc4e-fac9-b4bc-9a78-b81cf41f0633"},"perimeterState":"ENROLLED"},"deviceActionType":"INSTALL_APP"}]
20 | 2018-09-06T15:34:26.053-0500 - CORE Exchange[Body: DeviceActionEvent {"eventTypeId":"979dba5297b4c8c8a9fb59d25f33fd2a","timestamp":1536266065959,"tenantId":1,"tenantGuid":"5b73c758-57af-47b2-a6d4-d7b6c52cb5e5","externalTenantId":"S650643799","correlationId":"7876c65b-2ba4-7648-9a94-a6033312e34a","hostName":"svrbbp.mydomain.com","version":"5.63.87-SNAPSHOT","severity":"CLEARED","tags":["device_action","user","userdevice"],"userDeviceInfo":{"enrollmentType":"MDM_CONTROLS","perimeterUuid":"afa57869b-886a-7e74-a811-0730d2bb13c8","userInfo":{"userGuid":"af78905c-04df-4c0e-b491-6ea0ce6bed16","userName":"NBob003","emailAddress":"Marion.Cohen@mydomain.com"},"deviceInfo":{"deviceOSFamily":"ios","id":1254,"udid":"4a7783999478577b7746dc774657b992","guid":"6657bc4e-55c9-b4bc-9223-54723922a997"},"perimeterState":"ENROLLED"},"deviceActionType":"INSTALL_APP"}]
21 | 2018-09-06T16:27:41.420-0500 - CORE Exchange[Body: DeviceActionEvent {"eventTypeId":"979dba5297b4c8c8a9fb59d25f33fd2a","timestamp":1536269261342,"tenantId":1,"tenantGuid":"5b73c758-57af-47b2-a6d4-d7b6c52cb5e5","externalTenantId":"S650643799","correlationId":"7876c65b-2ba4-7648-9a94-2fb7b6479712","hostName":"svrbbp.mydomain.com","version":"5.63.87-SNAPSHOT","severity":"CLEARED","tags":["device_action","user","userdevice"],"userDeviceInfo":{"enrollmentType":"MDM_CONTROLS","perimeterUuid":"afa57869b-a8d8-7e74-98d7-a07c075a38bd","userInfo":{"userGuid":"af78905c-b049-4cf4-b491-d4b3bb81183c","userName":"NBOB376","emailAddress":"Jean.Blair@mydomain.com"},"deviceInfo":{"deviceOSFamily":"ios","id":1618,"udid":"4a7783999478577b7746dc774657b992","guid":"6657bc4e-fac9-b4bc-9a78-b81cf41f0633"},"perimeterState":"ENROLLED"},"deviceActionType":"INSTALL_APP"}]
22 | 2018-09-06T16:40:39.256-0500 - CORE Exchange[Body: DeviceActionEvent {"eventTypeId":"979dba5297b4c8c8a9fb59d25f33fd2a","timestamp":1536270039209,"tenantId":1,"tenantGuid":"5b73c758-57af-47b2-a6d4-d7b6c52cb5e5","externalTenantId":"S650643799","correlationId":"7876c65b-2ba4-7648-9a94-fb11e2160ee1","hostName":"svrbbp.mydomain.com","version":"5.63.87-SNAPSHOT","severity":"CLEARED","tags":["device_action","user","userdevice"],"userDeviceInfo":{"enrollmentType":"MDM_CONTROLS","perimeterUuid":"afa57869b-fe35-7e74-a823-2635d591079a","userInfo":{"userGuid":"af78905c-f687-42fd-b491-fe2791e42a40","userName":"NBob106","emailAddress":"Essie.Douglas@mydomain.com"},"deviceInfo":{"deviceOSFamily":"ios","id":1436,"udid":"4a7783999478577b7746dc774657b992","guid":"6657bc4e-eae0-b4bc-be57-abefee274bee"},"perimeterState":"ENROLLED"},"deviceActionType":"INSTALL_APP"}]
23 | 2018-09-06T21:29:14.549-0500 - CORE Exchange[Body: DeviceActionEvent {"eventTypeId":"979dba5297b4c8c8a9fb59d25f33fd2a","timestamp":1536287354517,"tenantId":1,"tenantGuid":"5b73c758-57af-47b2-a6d4-d7b6c52cb5e5","externalTenantId":"S650643799","correlationId":"7876c65b-2ba4-7648-9a94-8ec615c839dc","hostName":"svrbbp.mydomain.com","version":"5.63.87-SNAPSHOT","severity":"CLEARED","tags":["device_action","user","userdevice"],"userDeviceInfo":{"enrollmentType":"MDM_CONTROLS","perimeterUuid":"afa57869b-8067-7e74-88fa-2573f3e735a5","userInfo":{"userGuid":"af78905c-efdb-4810-b491-880e0746b757","userName":"NBFA117","emailAddress":"Jody.Collins@mydomain.com"},"deviceInfo":{"deviceOSFamily":"ios","id":1397,"udid":"4a7783999478577b7746dc774657b992","guid":"6657bc4e-2844-b4bc-877b-5ea155afadd5"},"perimeterState":"ENROLLED"},"deviceActionType":"INSTALL_APP"}]
24 | 2018-09-06T21:32:15.112-0500 - CORE Exchange[Body: DeviceActionEvent {"eventTypeId":"979dba5297b4c8c8a9fb59d25f33fd2a","timestamp":1536287535066,"tenantId":1,"tenantGuid":"5b73c758-57af-47b2-a6d4-d7b6c52cb5e5","externalTenantId":"S650643799","correlationId":"7876c65b-2ba4-7648-9a94-757ca5511383","hostName":"svrbbp.mydomain.com","version":"5.63.87-SNAPSHOT","severity":"CLEARED","tags":["device_action","user","userdevice"],"userDeviceInfo":{"enrollmentType":"MDM_CONTROLS","perimeterUuid":"afa57869b-061d-7e74-a885-4f9be29c4486","userInfo":{"userGuid":"af78905c-83e8-452d-b491-e82ca0d7f649","userName":"NBpac22","emailAddress":"Andre.Parker@mydomain.com"},"deviceInfo":{"deviceOSFamily":"ios","id":881,"udid":"4a7783999478577b7746dc774657b992","guid":"6657bc4e-53f8-b4bc-b581-85ef6ab20e0f"},"perimeterState":"ENROLLED"},"deviceActionType":"INSTALL_APP"}]
25 | 2018-09-06T21:32:15.112-0500 - CORE Exchange[Body: DeviceActionEvent {"eventTypeId":"979dba5297b4c8c8a9fb59d25f33fd2a","timestamp":1536287535081,"tenantId":1,"tenantGuid":"5b73c758-57af-47b2-a6d4-d7b6c52cb5e5","externalTenantId":"S650643799","correlationId":"7876c65b-2ba4-7648-9a94-757ca5511383","hostName":"svrbbp.mydomain.com","version":"5.63.87-SNAPSHOT","severity":"CLEARED","tags":["device_action","user","userdevice"],"userDeviceInfo":{"enrollmentType":"MDM_CONTROLS","perimeterUuid":"afa57869b-061d-7e74-a885-4f9be29c4486","userInfo":{"userGuid":"af78905c-83e8-452d-b491-e82ca0d7f649","userName":"NBpac22","emailAddress":"Andre.Parker@mydomain.com"},"deviceInfo":{"deviceOSFamily":"ios","id":881,"udid":"4a7783999478577b7746dc774657b992","guid":"6657bc4e-53f8-b4bc-b581-85ef6ab20e0f"},"perimeterState":"ENROLLED"},"deviceActionType":"INSTALL_APP"}]
--------------------------------------------------------------------------------
/ch11/04-Start-Count.ps1:
--------------------------------------------------------------------------------
1 | $TotalTime = 25
2 | $CurrentTime = 0
3 |
4 | while ($CurrentTime -le $TotalTime) {
5 | Write-Progress -Activity "Counting to $TotalTime" -Status "Elapsed time: $CurrentTime seconds" -PercentComplete ($CurrentTime / $TotalTime * 100)
6 | Start-Sleep 1
7 | $CurrentTime++
8 | }
--------------------------------------------------------------------------------
/ch11/05-Start-Count.ps1:
--------------------------------------------------------------------------------
1 | param ($TotalTime = 25)
2 |
3 | $CurrentTime = 0
4 |
5 | while ($CurrentTime -le $TotalTime) {
6 | Write-Progress -Activity "Counting to $TotalTime" -Status "Elapsed time: $CurrentTime seconds" -PercentComplete ($CurrentTime / $TotalTime * 100)
7 | Start-Sleep 1
8 | $CurrentTime++
9 | }
--------------------------------------------------------------------------------
/ch11/06-Start-Count.ps1:
--------------------------------------------------------------------------------
1 | function Start-Count {
2 | param ($TotalTime = 25)
3 |
4 | $CurrentTime = 0
5 |
6 | while ($CurrentTime -le $TotalTime) {
7 | Write-Progress -Activity "Counting to $TotalTime" -Status "Elapsed time: $CurrentTime seconds" -PercentComplete ($CurrentTime / $TotalTime * 100)
8 | Start-Sleep 1
9 | $CurrentTime++
10 | }
11 | }
--------------------------------------------------------------------------------
/ch11/07-Start-Count.ps1:
--------------------------------------------------------------------------------
1 | $MyScriptBlock = {
2 | param ($TotalTime = 25)
3 |
4 | $CurrentTime = 0
5 |
6 | while ($CurrentTime -le $TotalTime) {
7 | Write-Progress -Activity "Counting to $TotalTime" -Status "Elapsed time: $CurrentTime seconds" -PercentComplete ($CurrentTime / $TotalTime * 100)
8 | Start-Sleep 1
9 | $CurrentTime++
10 | }
11 | }
--------------------------------------------------------------------------------
/ch12/01-Start-Count.ps1:
--------------------------------------------------------------------------------
1 | function Start-Count {
2 | param (
3 | # The current time, or the starting point
4 | [Parameter(Mandatory=$true, Position=0)]
5 | [int]
6 | $CurrentTime,
7 |
8 | # The total number of seconds to count
9 | [Parameter(Mandatory=$true, Position=1)]
10 | [int]
11 | $TotalTime
12 | )
13 |
14 | while ($CurrentTime -le $TotalTime) {
15 | Write-Progress -Activity "Counting to $TotalTime" -Status "Counting: $CurrentTime seconds" -PercentComplete ($CurrentTime / $TotalTime * 100)
16 | Start-Sleep 1
17 | $CurrentTime++
18 | }
19 | }
--------------------------------------------------------------------------------
/ch12/01-Start-CountFlexible.ps1:
--------------------------------------------------------------------------------
1 | function Start-Count {
2 | param (
3 | # The current time, or the starting point
4 | [Parameter(Mandatory=$false)]
5 | [int]
6 | $CurrentTime=0,
7 |
8 | # The total number of seconds to count
9 | [Parameter(Mandatory=$true, Position=1)]
10 | [int]
11 | $TotalTime
12 | )
13 |
14 | while ($CurrentTime -le $TotalTime) {
15 | Write-Progress -Activity "Counting to $TotalTime" -Status "Counting: $CurrentTime seconds" -PercentComplete ($CurrentTime / $TotalTime * 100)
16 | Start-Sleep 1
17 | $CurrentTime++
18 | }
19 | }
--------------------------------------------------------------------------------
/ch12/02-Start-Count.ps1:
--------------------------------------------------------------------------------
1 | function Start-Count {
2 | param (
3 | # The current time, or the starting point
4 | [Parameter(Mandatory=$false)]
5 | [Alias("CT", "From")]
6 | [int]
7 | $CurrentTime=0,
8 |
9 | # The total number of seconds to count
10 | [Parameter(Mandatory=$true, Position=1)]
11 | [Alias("TT", "To")]
12 | [int]
13 | $TotalTime
14 | )
15 |
16 | while ($CurrentTime -le $TotalTime) {
17 | Write-Progress -Activity "Counting to $TotalTime" -Status "Counting: $CurrentTime seconds" -PercentComplete ($CurrentTime / $TotalTime * 100)
18 | Start-Sleep 1
19 | $CurrentTime++
20 | }
21 | }
--------------------------------------------------------------------------------
/ch12/03-New-PersonalMessage.ps1:
--------------------------------------------------------------------------------
1 | function New-PersonalMessage {
2 | [CmdletBinding(DefaultParameterSetName='Audio')]
3 | param (
4 | # The phone number
5 | [Parameter(Mandatory=$true, Position=0, ParameterSetName='Audio')]
6 | [Parameter(Mandatory=$true, Position=0, ParameterSetName='Text')]
7 | [string]
8 | $PhoneNumber,
9 |
10 | # The path to the WAV file
11 | [Parameter(Mandatory=$true, Position=1, ParameterSetName='Audio')]
12 | [string]
13 | $WavPath,
14 |
15 | # The message to be sent
16 | [Parameter(Mandatory=$true, Position=1, ParameterSetName='Text')]
17 | [string]
18 | $Message
19 | )
20 |
21 | if ($WavPath) {
22 | New-VoiceCall -PhoneNumber $PhoneNumber -FilePath $WavPath
23 | }
24 | else {
25 | Send-TextMessage -PhoneNumber $PhoneNumber -Message $Message
26 | }
27 | }
--------------------------------------------------------------------------------
/ch12/04-Start-Count.ps1:
--------------------------------------------------------------------------------
1 | function Start-Count {
2 | param (
3 | # The current time, or the starting point
4 | [Parameter(Mandatory=$false)]
5 | [Alias("CT", "From")]
6 | [int]
7 | $CurrentTime=0,
8 |
9 | # The total number of seconds to count
10 | [Parameter(Mandatory=$false, Position=1)]
11 | [Alias("TT", "To")]
12 | [int]
13 | $TotalTime=10
14 | )
15 |
16 | while ($CurrentTime -le $TotalTime) {
17 | Write-Progress -Activity "Counting to $TotalTime" -Status "Counting: $CurrentTime seconds" -PercentComplete ($CurrentTime / $TotalTime * 100)
18 | Start-Sleep 1
19 | $CurrentTime++
20 | }
21 | }
--------------------------------------------------------------------------------
/ch12/05-Start-Count.ps1:
--------------------------------------------------------------------------------
1 | function Start-Count {
2 | param (
3 | # The current time, or the starting point
4 | [Parameter(Mandatory=$false)]
5 | [Alias("CT", "From")]
6 | [int]
7 | $CurrentTime=0,
8 |
9 | # The total number of seconds to count
10 | [Parameter(Mandatory=$false, Position=1)]
11 | [Alias("TT", "To")]
12 | [ValidateSet(5, 10, 15, 20)]
13 | [int]
14 | $TotalTime=10
15 | )
16 |
17 | while ($CurrentTime -le $TotalTime) {
18 | Write-Progress -Activity "Counting to $TotalTime" -Status "Counting: $CurrentTime seconds" -PercentComplete ($CurrentTime / $TotalTime * 100)
19 | Start-Sleep 1
20 | $CurrentTime++
21 | }
22 | }
--------------------------------------------------------------------------------
/ch12/06-New-File.ps1:
--------------------------------------------------------------------------------
1 | function New-File {
2 | param (
3 | # The path to the file (or the name)
4 | [Parameter(Mandatory=$true, Position=0)]
5 | [string[]]
6 | $Path
7 | )
8 | begin {
9 | Write-Host "$(Get-Date)"
10 | }
11 | process {
12 | foreach ($Item in $Path) {
13 | New-Item -Path $Item -ItemType File
14 | }
15 | }
16 | end {}
17 | }
--------------------------------------------------------------------------------
/ch12/07-New-File.ps1:
--------------------------------------------------------------------------------
1 | function New-File {
2 | [CmdletBinding(
3 | ConfirmImpact='High',
4 | SupportsShouldProcess=$true
5 | )]
6 | param (
7 | # The path to the file (or the name)
8 | [Parameter(Mandatory=$true, Position=0)]
9 | [string[]]
10 | $Path
11 | )
12 | begin {
13 | Write-Host "$(Get-Date)"
14 | }
15 | process {
16 | foreach ($Item in $Path) {
17 | if ($PSCmdlet.ShouldProcess("$PsScriptRoot", "Create $Path")) {
18 | New-Item -Path $Item -ItemType File
19 | }
20 | }
21 | }
22 | end {}
23 | }
--------------------------------------------------------------------------------
/ch12/08-Start-Count.ps1:
--------------------------------------------------------------------------------
1 | function Start-Count {
2 | <#
3 | .SYNOPSIS
4 | This cmdlet counts seconds by accepting a from and a to value. The from value is optional.
5 |
6 | .DESCRIPTION
7 | This cmdlet is a counting function. It accepts two parameters: the TotalTime being the "to" and CurrentTime being the "from". CurrentTime defaults to 0 if not specified.
8 |
9 | .PARAMETER CurrentTime
10 | The starting point, in seconds.
11 |
12 | .PARAMETER TotalTime
13 | The stopping point, in seconds.
14 |
15 | .EXAMPLE
16 | Start-Count 10 15
17 |
18 | .NOTES
19 | Created as a demo for PowerShell 6.0 Linux Administration Cookbook
20 | #>
21 | param (
22 | # The current time, or the starting point
23 | [Parameter(Mandatory=$false)]
24 | [Alias("CT", "From")]
25 | [int]
26 | $CurrentTime=0,
27 |
28 | # The total number of seconds to count
29 | [Parameter(Mandatory=$false, Position=1)]
30 | [Alias("TT", "To")]
31 | [ValidateSet(5, 10, 15, 20)]
32 | [int]
33 | $TotalTime=10
34 | )
35 |
36 | while ($CurrentTime -le $TotalTime) {
37 | Write-Progress -Activity "Counting to $TotalTime" -Status "Counting: $CurrentTime seconds" -PercentComplete ($CurrentTime / $TotalTime * 100)
38 | Start-Sleep 1
39 | $CurrentTime++
40 | }
41 | }
--------------------------------------------------------------------------------
/ch12/09-New-File.ps1:
--------------------------------------------------------------------------------
1 | function New-File {
2 | [CmdletBinding(
3 | ConfirmImpact='High',
4 | SupportsShouldProcess=$true
5 | )]
6 | param (
7 | # The path to the file (or the name)
8 | [Parameter(Mandatory=$true, Position=0, ValueFromPipeline)]
9 | [string[]]
10 | $Path
11 | )
12 | begin {
13 | Write-Host "$(Get-Date)"
14 | }
15 | process {
16 | foreach ($Item in $Path) {
17 | if ($PSCmdlet.ShouldProcess("$PsScriptRoot", "Create $Item")) {
18 | New-Item -Path $Item -ItemType File
19 | }
20 | }
21 | }
22 | end {}
23 | }
--------------------------------------------------------------------------------
/ch12/10-New-File.ps1:
--------------------------------------------------------------------------------
1 | function Main {
2 | New-FileName -Count 10 | New-File
3 | }
4 |
5 | function New-FileName {
6 | param (
7 | # The name of the file
8 | [Parameter(Mandatory=$false)]
9 | [string]
10 | $Prefix='File',
11 |
12 | # The number of files to be generated
13 | [Parameter(Mandatory=$false, Position=1)]
14 | [int]
15 | $Count=1
16 | )
17 |
18 | begin {
19 | $InitCount = 1
20 | }
21 |
22 | process {
23 | while ($InitCount -le $Count) {
24 | Write-Output $Prefix$InitCount
25 | $InitCount++
26 | }
27 | }
28 | }
29 |
30 | function New-File {
31 | [CmdletBinding(
32 | ConfirmImpact='High',
33 | SupportsShouldProcess=$true
34 | )]
35 | param (
36 | # The path to the file (or the name)
37 | [Parameter(Mandatory=$true, Position=0, ValueFromPipeline)]
38 | [string[]]
39 | $Path
40 | )
41 | begin {
42 | Write-Host "$(Get-Date)"
43 | }
44 | process {
45 | foreach ($Item in $Path) {
46 | if ($PSCmdlet.ShouldProcess("$PsScriptRoot", "Create $Item")) {
47 | New-Item -Path $Item -ItemType File
48 | }
49 | }
50 | }
51 | end {}
52 | }
53 |
54 | . Main
--------------------------------------------------------------------------------
/ch12/11-New-File.psm1:
--------------------------------------------------------------------------------
1 | function New-FileName {
2 | param (
3 | # The name of the file
4 | [Parameter(Mandatory=$false)]
5 | [string]
6 | $Prefix='File',
7 |
8 | # The number of files to be generated
9 | [Parameter(Mandatory=$false, Position=1)]
10 | [int]
11 | $Count=1
12 | )
13 |
14 | begin {
15 | $InitCount = 1
16 | }
17 |
18 | process {
19 | while ($InitCount -le $Count) {
20 | Write-Output $Prefix$InitCount
21 | $InitCount++
22 | }
23 | }
24 | }
25 |
26 | function New-File {
27 | [CmdletBinding(
28 | SupportsShouldProcess=$true,
29 | DefaultParameterSetName='File'
30 | )]
31 | param (
32 | # The path to the file (or the name)
33 | [Parameter(Mandatory=$true, Position=0, ValueFromPipeline, ParameterSetName='File')]
34 | [string[]]
35 | $Path,
36 |
37 | # Whether files need to be generated
38 | [Parameter(Mandatory=$true, ParameterSetName='Generate')]
39 | [switch]
40 | $Generate,
41 |
42 | # Number of files to be generated
43 | [Parameter(Mandatory=$false, ParameterSetName='Generate')]
44 | [int]
45 | $Count=1
46 | )
47 | begin {
48 | Write-Host "$(Get-Date)"
49 | }
50 | process {
51 | if ($Generate) {
52 | $Path = New-FileName -Count $Count
53 | }
54 | foreach ($Item in $Path) {
55 | if ($PSCmdlet.ShouldProcess("$PsScriptRoot", "Create $Item")) {
56 | New-Item -Path $Item -ItemType File
57 | }
58 | }
59 | }
60 | end {}
61 | }
62 |
63 | Export-ModuleMember New-File
--------------------------------------------------------------------------------
/ch12/12-New-File.psm1:
--------------------------------------------------------------------------------
1 | function New-FileName {
2 | param (
3 | # The name of the file
4 | [Parameter(Mandatory=$false)]
5 | [string]
6 | $Prefix='File',
7 |
8 | # The number of files to be generated
9 | [Parameter(Mandatory=$false, Position=1)]
10 | [int]
11 | $Count=1
12 | )
13 |
14 | begin {
15 | $InitCount = 1
16 | }
17 |
18 | process {
19 | while ($InitCount -le $Count) {
20 | Write-Output $Prefix$InitCount
21 | $InitCount++
22 | }
23 | }
24 | }
25 |
26 | function New-File {
27 | [CmdletBinding(
28 | SupportsShouldProcess=$true,
29 | DefaultParameterSetName='File'
30 | )]
31 | param (
32 | # The path to the file (or the name)
33 | [Parameter(Mandatory=$true, Position=0, ValueFromPipeline, ParameterSetName='File')]
34 | [string[]]
35 | $Path,
36 |
37 | # Whether files need to be generated
38 | [Parameter(Mandatory=$true, ParameterSetName='Generate')]
39 | [switch]
40 | $Generate,
41 |
42 | # Number of files to be generated
43 | [Parameter(Mandatory=$false, ParameterSetName='Generate')]
44 | [int]
45 | $Count=1
46 | )
47 | begin {
48 | Write-Host "$(Get-Date)"
49 | }
50 | process {
51 | if ($Generate) {
52 | $Path = New-FileName -Count $Count
53 | }
54 | foreach ($Item in $Path) {
55 | if ($PSCmdlet.ShouldProcess("$PsScriptRoot", "Create $Item")) {
56 | New-Item -Path $Item -ItemType File
57 | }
58 | }
59 | }
60 | end {}
61 | }
62 |
63 | Export-ModuleMember New-File
64 |
65 | $MyInvocation.MyCommand.ScriptBlock.Module.OnRemove = {
66 | Write-Output "Module cleaned up."
67 | }
68 |
69 | Register-EngineEvent PowerShell.Exiting {
70 | Remove-Module '12-New-File'
71 | }
--------------------------------------------------------------------------------
/ch13/01-New-File.ps1:
--------------------------------------------------------------------------------
1 | function New-File {
2 | [CmdletBinding()]
3 | param (
4 | # The path to the file (or the name)
5 | [Parameter(Mandatory=$true, Position=0)]
6 | [string[]]
7 | $Path
8 | )
9 | Write-Debug "Entered the process block."
10 | foreach ($Item in $Path) {
11 | Write-Debug "Iterating for item, $Item."
12 | New-Item -Path $Item -ItemType File
13 | }
14 | }
--------------------------------------------------------------------------------
/ch13/02-New-File.ps1:
--------------------------------------------------------------------------------
1 | function New-File {
2 | [CmdletBinding()]
3 | param (
4 | # The path to the file (or the name)
5 | [Parameter(Mandatory=$true, Position=0)]
6 | [string[]]
7 | $Path
8 | )
9 | begin {
10 | Write-Debug "Entered the begin block."
11 | Write-Host "$(Get-Date)"
12 | }
13 | process {
14 | Write-Debug "Entered the process block."
15 | foreach ($Item in $Path) {
16 | Write-Debug "Iterating for item, $Item."
17 | New-Item -Path $Item -ItemType File
18 | }
19 | }
20 | end {
21 | Write-Debug "Entered the end block."
22 | }
23 | }
--------------------------------------------------------------------------------
/ch13/03-Set-Name.ps1:
--------------------------------------------------------------------------------
1 | function Set-Name {
2 | $Name = @()
3 | $Name = Read-Host "Enter first name"
4 | $Name += Read-Host "Enter middle name (press Enter for blank)"
5 | $Name += Read-Host "Enter surname"
6 |
7 | $Count = $Name.Count
8 | $Converter = (Get-Culture).TextInfo
9 |
10 | switch ($Count) {
11 | 2 {
12 | "$($Converter.ToTitleCase($Name[1])), $($Converter.ToTitleCase($Name[0]))"
13 | }
14 | 3 {
15 | "$($Converter.ToTitleCase($Name[2])), $($Converter.ToTitleCase($Name[0])) $($Converter.ToTitleCase($Name[1]))"
16 | }
17 | Default {
18 | Write-Host "Invalid input."
19 | }
20 | }
21 | }
--------------------------------------------------------------------------------
/ch13/04-New-File.ps1:
--------------------------------------------------------------------------------
1 | function New-File {
2 | [CmdletBinding()]
3 | param (
4 | # The path to the file (or the name)
5 | [Parameter(Mandatory=$true, Position=0)]
6 | [string[]]
7 | $Path
8 | )
9 | begin {
10 | Write-Debug "Entered the begin block."
11 | Write-Host "$(Get-Date)"
12 | }
13 | process {
14 | Write-Debug "Entered the process block."
15 | foreach ($Item in $Path) {
16 | Write-Debug "Iterating for item, $Item."
17 | New-Item -Path $Item -ItemType File
18 | }
19 | }
20 | end {
21 | Write-Debug "Entered the end block."
22 | }
23 | }
24 |
25 | New-File One.txt
--------------------------------------------------------------------------------
/ch13/05-Set-Name.ps1:
--------------------------------------------------------------------------------
1 | function Set-Name {
2 | $Name = @()
3 | $Name = Read-Host "Enter first name"
4 | $Name += Read-Host "Enter middle name (press Enter for blank)"
5 | $Name += Read-Host "Enter surname"
6 |
7 | $Count = $Name.Count
8 | $Converter = (Get-Culture).TextInfo
9 |
10 | switch ($Count) {
11 | 2 {
12 | "$($Converter.ToTitleCase($Name[1])), $($Converter.ToTitleCase($Name[0]))"
13 | }
14 | 3 {
15 | "$($Converter.ToTitleCase($Name[2])), $($Converter.ToTitleCase($Name[0])) $($Converter.ToTitleCase($Name[1]))"
16 | }
17 | Default {
18 | Write-Host "Invalid input."
19 | }
20 | }
21 | }
22 | Set-Name
--------------------------------------------------------------------------------
/ch13/06-Find-Item.ps1:
--------------------------------------------------------------------------------
1 | ping ghostname
2 |
3 | if (!$?) {
4 | Write-Host "PowerShell seems to have encountered an error while running the last command."
5 | }
6 |
7 | Write-Host "The exit code for the last operation is $LASTEXITCODE."
8 |
9 | Remove-Variable LASTEXITCODE
10 |
11 | Get-Item $HOME/random/randompackage.zip -ErrorAction SilentlyContinue
12 |
13 | if (!$?) {
14 | Write-Host "PowerShell seems to have encountered an error while running the last command."
15 | }
16 |
17 | Write-Host "The exit code for the last operation is $LASTEXITCODE."
--------------------------------------------------------------------------------
/ch13/07-Find-Item.ps1:
--------------------------------------------------------------------------------
1 | Get-Item $HOME/random/randompackage.zip -ErrorAction SilentlyContinue
2 |
3 | if (!$?) {
4 | Write-Host "PowerShell seems to have encountered an error while running the last command."
5 | }
6 |
7 | $Error | Select-Object -Property *
--------------------------------------------------------------------------------
/ch13/08-New-LogFile.ps1:
--------------------------------------------------------------------------------
1 | function New-LogFile {
2 | param (
3 | # The path to the log file
4 | [Parameter(Mandatory=$false)]
5 | [string]
6 | $Path = "$HOME/random/LogDir",
7 |
8 | # The name of the log file
9 | [Parameter(Mandatory=$false)]
10 | [string]
11 | $Name = 'MyLog.log'
12 | )
13 |
14 | try {
15 | New-Item "$Path/$Name" -ItemType File -ErrorAction Stop
16 | }
17 | catch [System.IO.DirectoryNotFoundException] {
18 | New-Item $Path -ItemType Directory -Force
19 | New-LogFile
20 | }
21 | catch {
22 | "Some error other than DirectoryNotFound"
23 | }
24 | }
--------------------------------------------------------------------------------
/ch13/09-New-LogFile.ps1:
--------------------------------------------------------------------------------
1 | function New-LogFile {
2 | param (
3 | # The path to the log file
4 | [Parameter(Mandatory=$false)]
5 | [string]
6 | $Path = "$HOME/random/LogDir",
7 |
8 | # The name of the log file
9 | [Parameter(Mandatory=$false)]
10 | [string]
11 | $Name = 'MyLog.log'
12 | )
13 |
14 | try {
15 | Write-Verbose "Creating the file, $Name at $Path."
16 | New-Item "$Path/$Name" -ItemType File -ErrorAction Stop
17 | }
18 | catch [System.IO.DirectoryNotFoundException] {
19 | Write-Verbose "System.IO.DirectoryNotFoundException encountered."
20 | Write-Verbose "Creating the directory, $Path."
21 | New-Item $Path -ItemType Directory -Force
22 | Write-Verbose "Calling the function."
23 | New-LogFile
24 | }
25 | catch {
26 | Write-Verbose "Catch-all. There was an error."
27 | Write-Error $_
28 | }
29 | }
30 | New-LogFile -Verbose 4>> verbose.log 2>> error.log
--------------------------------------------------------------------------------
/ch14/01-PoSH-Remote-Query.ps1:
--------------------------------------------------------------------------------
1 |
2 | Import-Csv ./input.csv|% { Invoke-Command -HostName $_.Server -UserName $_.User -ScriptBlock { Param ([string]$Server)
3 | Get-Process | Sort-Object CPU-Descending |`
4 | Select-Object Handles, CPU, `
5 | @{name = "NPM"; Expression = {[int]($_.NPM / 1024)}}, `
6 | @{name = "PM"; Expression = {[int]($_.PM / 1024)}}, `
7 | @{name = "WS"; Expression = {[int]($_.WS / 1024)}}, `
8 | @{name = "VM"; Expression = {[int]($_.VM / 1MB)}},`
9 | @{name = "ServerName"; Expression = {($Server)}},`
10 | Id, ProcessName -First 5
11 | }-Args $_.Server
12 | }
13 |
--------------------------------------------------------------------------------
/ch14/02-PoSH-Remote-Query-HTML.ps1:
--------------------------------------------------------------------------------
1 | $Top = @()
2 |
3 | $process =Import-Csv ./input.csv|% { Invoke-Command -HostName $_.Server -UserName $_.User -ScriptBlock { Param($Server)
4 | Get-Process | Sort-Object CPU-Descending |`
5 | Select-Object Handles, CPU, `
6 | @{name = "NPM"; Expression = {[int]($_.NPM / 1024)}}, `
7 | @{name = "PM"; Expression = {[int]($_.PM / 1024)}}, `
8 | @{name = "WS"; Expression = {[int]($_.WS / 1024)}}, `
9 | @{name = "VM"; Expression = {[int]($_.VM / 1MB)}},`
10 | @{name = "ServerName"; Expression = {($server)}},`
11 | Id, ProcessName -First 5
12 | }-Args $_.Server
13 | }
14 |
15 | foreach ($proc in $process) {
16 |
17 | $row = New-Object -Type PSObject -Property @{
18 | ServerName = $proc.Servername
19 | ID = $proc.ID
20 | ProcessName = $proc.ProcessName
21 | NPM_KB = $proc.NPM
22 | PM_KB = $proc.PM
23 | WS_KB = $proc.WS
24 | VM_MB = $proc.VM
25 | CPU_S = $proc.CPU
26 | }
27 | $Top += $row
28 | }
29 |
30 | $Top | ConvertTo-Html |Out-File /tmp/out.html
31 |
--------------------------------------------------------------------------------
/ch14/03-PoSH-Remote-Query-HTML-Mail.ps1:
--------------------------------------------------------------------------------
1 | #inputfile - filelocation of the CSV file
2 | $inputfile='/tmp/input.CSV'
3 |
4 | #Ouput file
5 | $outfile='/tmp/out.html'
6 | #Email variable declaration
7 | $from = 'donotreply@packtpublinux.com'
8 | $to = 'pjayaram@gmail.com'
9 | $cc = 'pjayaram@gmail.com'
10 | $sub = 'Process Info-PowerShell Remoting'
11 | $body = 'PowerShell script automation email to pull process related information from Windows and Linux machines'
12 | $attachment = $outfile
13 | $smtpserver = 'packpublinux@smtp.com'
14 |
15 | #declare the array to hold multiple values
16 | $Top = @()
17 | #the output of import-csv is assigned to a variable
18 | $process =Import-Csv $inputfile|% { Invoke-Command -HostName $_.Server -UserName $_.User -ScriptBlock { Param($Server)
19 | Get-Process | Sort-Object CPU-Descending |`
20 | Select-Object Handles, CPU, `
21 | @{name = "NPM"; Expression = {[int]($_.NPM / 1024)}}, `
22 | @{name = "PM"; Expression = {[int]($_.PM / 1024)}}, `
23 | @{name = "WS"; Expression = {[int]($_.WS / 1024)}}, `
24 | @{name = "VM"; Expression = {[int]($_.VM / 1MB)}},`
25 | @{name = "ServerName"; Expression = {($server)}},`
26 | Id, ProcessName -First 5 }-Args $_.Server
27 | }
28 | foreach ($proc in $process)
29 | {
30 | $row = New-Object -Type PSObject -Property @{
31 | ServerName = $proc.Servername
32 | ID = $proc.ID
33 | ProcessName = $proc.ProcessName
34 | NPM_KB = $proc.NPM
35 | PM_KB = $proc.PM
36 | WS_KB = $proc.WS
37 | VM_MB = $proc.VM
38 | CPU_S = $proc.CPU
39 | }
40 | $Top += $row
41 | }
42 | $Top | ConvertTo-Html |Out-File $outfile
43 |
44 | #Send Email outout to intended receipients
45 |
46 | $message = new-object System.Net.Mail.MailMessage
47 | $message.From = $from
48 | $message.To.Add($to)
49 | $message.CC.Add($cc)
50 | $message.IsBodyHtml = $True
51 | $message.Subject = $sub
52 | $attach = new-object Net.Mail.Attachment($attachment)
53 | $message.Attachments.Add($attach)
54 | $message.body = $body
55 | $smtp = new-object Net.Mail.SmtpClient($smtpserver)
56 | $smtp.Send($message)
--------------------------------------------------------------------------------
/ch14/Input.CSV:
--------------------------------------------------------------------------------
1 | Server,user
2 | hfd01,ssh-test
3 | 10.2.6.68,prashant
4 |
--------------------------------------------------------------------------------
/ch15/SampleAzureRmVM.ps1:
--------------------------------------------------------------------------------
1 | Param(
2 | # Variables for common values
3 | [string]$resourceGroup = "packtpub-rg",
4 | [string]$storageAcctName ="packtstorage",
5 | [string]$location = "East US",
6 | [string]$vnetName="packtpub-vnet",
7 | [string]$NicName="packtpub-vm-nic",
8 | [string]$diskname="packtUbuntu",
9 | [string]$vmName = "packtpub-ubuntu"
10 | )
11 |
12 |
13 | #Check for open session
14 | Connect-AzureRmAccount
15 |
16 | # Create user object
17 | $cred = Get-Credential -Message "Enter username and password of administrator crendentials"
18 |
19 | # Create a resource group
20 | New-AzureRmResourceGroup -Name $resourceGroup -Location $location
21 |
22 | #Create a storage account
23 | New-AzureRmStorageAccount -Name $storageAcctName -ResourceGroupName $resourceGroup -Type Standard_LRS -Location $location
24 |
25 |
26 | # Create a subnet configuration
27 | $subnetCfg = New-AzureRmVirtualNetworkSubnetConfig -Name mySubnet -AddressPrefix 10.0.1.0/24
28 |
29 | # Create a virtual network
30 | $vnet=New-AzureRmVirtualNetwork -Name $vnetName -ResourceGroupName $resourceGroup -Location $location -AddressPrefix 10.0.0.0/16 -Subnet $subnetCfg
31 |
32 | # Create a public IP address and specify a DNS name
33 |
34 |
35 | # Create a virtual network card and associate with public IP address and NSG
36 | $nic=New-AzureRmNetworkInterface -Name $nicname -ResourceGroupName $resourceGroup -Location $location -SubnetId $vnet.Subnets[0].Id -PublicIpAddressId $IP.Id
37 |
38 |
39 | #Create a blob storage
40 | $storageAccount=Get-AzureRmStorageAccount -ResourceGroupName $resourceGroup -Name $storageAcctName
41 | $osdiskuri=$storageAccount.PrimaryEndpoints.Blob.ToString()+'vhds/'+$diskname+".vhd"
42 |
43 | # Create a virtual machine configuration
44 | $vm =New-AzureRmVMConfig -VMName $vmname -VMSize "Basic_A1"
45 | $vm=Set-AzureRmVMOperatingSystem -VM $vm -Linux -ComputerName $vmname -Credential $cred
46 | $vm=Set-AzureRmVMSourceImage -VM $vm -PublisherName 'Canonical' -Offer 'UbuntuServer' -Skus '18.04-LTS' -Version 'latest'
47 | $vm=Add-AzureRmVMNetworkInterface -VM $vm -id $nic.Id
48 | $vm=Set-AzureRmVMOSDisk -VM $vm -Name $diskname -VhdUri $osdiskuri -CreateOption fromImage
49 |
50 |
51 |
52 | # Create a virtual machine
53 | New-AzureRmVM -ResourceGroupName $resourceGroup -Location $location -VM $vm
--------------------------------------------------------------------------------
/ch16/Install-SqlServer.ps1:
--------------------------------------------------------------------------------
1 | # Run this as an administrator.
2 |
3 | Set-PSRepository -Name PsGallery -InstallationPolicy Trusted
4 |
5 | Install-Module SqlServer
6 |
7 | if ((Get-Module -ListAvailable).Name -contains 'SqlServer') {
8 | Get-Command -CommandType Cmdlet | Where-Object Source -Match 'SQL' | Group-Object Source
9 | }
--------------------------------------------------------------------------------
/ch16/New-DataFormatExample.ps1:
--------------------------------------------------------------------------------
1 | #Define Input variables
2 | $dataSource = "10.2.6.50"
3 | #Define the login credentials for SQL authentication
4 | $user = "SA"
5 | $pwd = "thanVitha@2015"
6 | #Define the database name from which the data is going to be read
7 | $database = "PacktPub"
8 | #Build the connection string
9 | $connStr = "Server=$dataSource;uid=$user; pwd=$pwd;Database=$database;Integrated Security=False;"
10 | #Prepare the query
11 | $query = "SELECT * FROM TaskManagerDump"
12 | #Instantiate the sqlConnection namespace
13 | $Conn = New-Object System.Data.SqlClient.SqlConnection
14 | $Conn.ConnectionString = $connStr
15 | #Open the connection
16 | $Conn.Open()
17 | #Create sub-objects to the Main object $Conn
18 | $cmd = $Conn.CreateCommand()
19 | #Assign the Query text to a $command object
20 | $cmd.CommandText = $query
21 | #Execute the adapter
22 | $resultset = $cmd.ExecuteReader()
23 | #Create an object DataTable namespace
24 | $table = new-object "System.Data.DataTable"
25 | #Load the data to the table
26 | $table.Load($resultset)
27 | $table |Where-Object {$_.ProcessName -match "pwsh"}
28 | #$table |Where-Object {$_.ProcessName -match "pwsh"} | format-table -autosize
29 | #$table |Where-Object {$_.ProcessName -match "pwsh"} | format-list
30 | #$table |Where-Object {$_.ProcessName -match "pwsh"} | format-table $format
31 | #$table | Where-Object {$_.ProcessName -match "pwsh"}| format-table $format | Out-File /tmp/output.txt
32 | $Conn.Close()
--------------------------------------------------------------------------------
/ch16/New-GetProcessRepo.ps1:
--------------------------------------------------------------------------------
1 | #Import the SqlServer Module
2 | Import-Module -Name Sqlserver
3 | #The Linux SQL Instance IP Address
4 | $SQLServer='10.2.6.50'
5 | #Define credential details
6 | $User='SA'
7 | #Convert password text to a secure string
8 | $Pass=ConvertTo-SecureString 'thanVitha@2015' -AsPlainText -Force
9 | #Build the credetial using securing string
10 | $cred=New-Object -TypeName System.Management.Automation.PSCredential -ArgumentList $User,$Pass
11 | (Get-Process | Select-Object -Property ` Id,ProcessName,StartTime,UserProcessorTime,WorkingSet,Description) | `
12 | Write-SqlTableData -Credential $cred -ServerInstance "localhost" -DatabaseName `
13 | "PacktPub" -SchemaName "dbo" -TableName "TaskManagerDump" -Force
--------------------------------------------------------------------------------
/ch16/New-MultiServerTsql.ps1:
--------------------------------------------------------------------------------
1 | #Import the SqlServer module
2 | Import-Module –Name SqlServer
3 |
4 | #Read the CSV file content using Import-CSV cmdlet
5 | Import-Csv -Path $filepath|ForEach-Object {
6 |
7 | #The Linux SQL Instance IP Address
8 | $SQLServer=$_.InstanceName
9 |
10 | #Define credential details
11 | $User=$_.Username
12 |
13 | #Convert password text to a secure string
14 | $Pass=ConvertTo-SecureString $_.Password -AsPlainText -Force
15 |
16 | #Build the credential using securing string
17 | $cred=New-Object -TypeName System.Management.Automation.PSCredential -ArgumentList $User,$Pass
18 | $SQLServerObject=New-Object Microsoft.SqlServer.Management.Smo.Server $SQLServer
19 | $SQLServerObject.ConnectionContext.LoginSecure=$false
20 | $SQLServerObject.ConnectionContext.set_login($cred.Username)
21 | $SQLServerObject.ConnectionContext.set_SecurePassword($cred.Password)
22 |
23 | #Handle the exceptions using Try and Catch method
24 | try
25 | { #Build connection to the Local SQL Instance
26 | $SQLServerObject.ConnectionContext.connect()
27 | $db=New-Object Microsoft.SqlServer.Management.Smo.Database $SQLServerObject,'PacktPub'
28 | $db.Create()
29 | }
30 | catch
31 | {
32 | #Write the exception message
33 | write-Error $_.Exception.message
34 | }
35 | finally
36 | {
37 | #Close the connection
38 | $SQLServerObject.ConnectionContext.Disconnect()
39 | }
40 | }
--------------------------------------------------------------------------------
/ch16/New-TsqlQuery.ps1:
--------------------------------------------------------------------------------
1 | $SQLServer='hqdbt01'
2 | $SQLServerObject=New-Object Microsoft.SqlServer.Management.Smo.Server $SQLServer
3 | $SQLServerObject.ConnectionContext.LoginSecure=$false
4 | $SQLServerObject.ConnectionContext.set_login("SA")
5 | $SQLServerObject.ConnectionContext.set_Password("PackPub@2018")
6 | $SQLServerObject.Information | Select-Object FullyQualifiedNetName, Parent, Version, Edition | Format-Table -AutoSize
--------------------------------------------------------------------------------
/ch16/program.cs:
--------------------------------------------------------------------------------
1 | // Replace the Program.cs that got created when you ran `dotnet new console`
2 |
3 | using System;
4 | namespace PacktPub {
5 | class Program {
6 | static void Main(string[] args) {
7 | Console.WriteLine("Introduction to .Net Core on Linux!");
8 | }
9 | }
10 | }
--------------------------------------------------------------------------------
/ch17/PoSH-Find-DockerTags.ps1:
--------------------------------------------------------------------------------
1 | function Get-AllImages {
2 | param(
3 | # Get the base image name
4 | [Parameter(Mandatory=$true)]
5 | [string]
6 | $Repo
7 | )
8 | begin {
9 | $UriTest = Invoke-WebRequest "https://registry.hub.docker.com/v1/repositories/$Repo/tags" -DisableKeepAlive -UseBasicParsing
10 | if ($UriTest.StatusCode -eq 200) {
11 | # Just proceed
12 | }
13 | else {
14 | break
15 | }
16 | }
17 | process {
18 | (Invoke-WebRequest "https://registry.hub.docker.com/v1/repositories/$Repo/tags" | ConvertFrom-Json).SyncRoot.Name
19 | }
20 | }
21 |
22 | # Call the function as `Get-AllImages -Repo centos`
--------------------------------------------------------------------------------
/ch17/PoSH-Setup-Docker.ps1:
--------------------------------------------------------------------------------
1 | #Define the array of elements [1,2,3]
2 | 1,2,3|foreach-object {
3 | #Build the name of the servers. Its going to be like PackPubDemo1,PackPubDemo2,PackPubDemo3
4 | $name='PackPubDemo'+$_
5 | #print the name of docker containers
6 | write-host $name
7 | try
8 | {
9 | #integrate the powershell variable with the docker cli command
10 | docker run -e 'ACCEPT_EULA=Y' -e 'MSSQL_SA_PASSWORD=PacktPubDemo$2018' --name $name -d microsoft/mssql-server-linux:2017-latest
11 | }
12 | catch
13 | {
14 | #Handle exception
15 | write-host $_.Exception.Message
16 | }
17 | }
--------------------------------------------------------------------------------
/cheatsheets/chapter-01.md:
--------------------------------------------------------------------------------
1 | # Introducing PowerShell Core
2 |
3 | Get help on any command:
4 |
5 | ```powershell
6 | # Get-Help
7 | Get-Help Get-Command
8 | ```
9 |
10 | Get more help on a certain cmdlet (e.g. `Get-Command`):
11 |
12 | ```powershell
13 | # Full help text
14 | Get-Help Get-Command -Full
15 |
16 | # Show examples
17 | Get-Help Get-Command -Examples
18 |
19 | # Read the help in a browser
20 | Get-Help Get-Command -Online
21 | ```
22 |
23 | Update the help information:
24 |
25 | ```powershell
26 | Update-Help
27 | ```
28 |
29 | Select specific string from the output:
30 |
31 | ```powershell
32 | Get-Help Get-Command | Out-String -Stream | Select-String 'common'
33 | ```
34 |
35 | Get help on a specific parameter:
36 |
37 | ```powershell
38 | Get-Help Get-Command -Parameter Noun
39 | ```
40 |
41 | Work with `about_` topics:
42 |
43 | ```powershell
44 | # List out all the `about_` topics
45 | Get-Help about_*
46 |
47 | # Pick the topic you would like to read about and then
48 | Get-Help about_Modules
49 | ```
50 |
51 | Search for cmdlets:
52 |
53 | ```powershell
54 | # Discover cmdlets based on the noun
55 | Get-Command -Noun Process
56 |
57 | # Dicsover cmdlets based on the verb as well
58 | Get-Command -Verb Get -Noun Process
59 |
60 | # Dicsover cmdlets based on the module
61 | Get-Command -Noun Process -Module Microsoft.PowerShell.Management
62 | ```
63 |
64 | Search for a module in the PowerShell Gallery
65 |
66 | ```powershell
67 | Find-Module 'Docker'
68 | ```
69 |
70 | Install a module:
71 |
72 | ```powershell
73 | # Install directly from the PowerShell Gallery
74 | Install-Module 'Docker'
75 |
76 | # To save the module and import it instead
77 | # Create a folder where you would like to store the modules:
78 | New-Item -ItemType Directory -Path ~/PSModules
79 |
80 | # Save the module in the directory you just created
81 | Save-Module Docker ~/PsModules
82 |
83 | # Import the module
84 | Import-Module ~/PsModules/Docker/1.3.2/Docker.psm1
85 | ```
86 |
87 | Update a module:
88 |
89 | ```powershell
90 | Update-Module Docker
91 | ```
92 |
93 | Remove a module from the system:
94 |
95 | ```powershell
96 | # Would work on the modules installed with `Install-Module`
97 | Uninstall-Module Docker
98 |
99 | # For modules you saved, simply delete the directory that contains the module files
100 | Remove-Item ~/PsModules/Docker -Recurse
101 | ```
102 |
103 | List out all the providers in PowerShell:
104 |
105 | ```powershell
106 | Get-PsProvider
107 | ```
108 |
109 | Navigate to one of the drives in one of the providers:
110 |
111 | ```powershell
112 | Set-Location Alias:
113 | ```
114 |
115 | Get information on a certain directory:
116 |
117 | ```powershell
118 | # Using the .NET class
119 | New-Object -TypeName System.IO.DirectoryInfo -ArgumentList '/home/ram'
120 |
121 | # Using PowerShell
122 | Get-Item '/home/ram'
123 | ```
124 |
125 | Get the members that are part of the returned object:
126 |
127 | ```powershell
128 | Get-Item '/home/ram' | Get-Member
129 | ```
130 |
131 | Get one of the members from the output:
132 |
133 | ```powershell
134 | # Find the time the directory was written to, last
135 | (Get-Item /home/ram).LastWriteTime
136 |
137 | # Find the parent of the directory
138 | (Get-Item /home/ram).Parent
139 |
140 | # Find the time the parent was created
141 | (Get-Item /home/ram).Parent.CreationTime
142 |
143 | # Pick just the year property
144 | (Get-Item /home/ram).Parent.CreationTime.Year
145 | ```
146 |
147 | Create a subdirectory within a directory using one of the methods available in the output object:
148 |
149 | ```powershell
150 | (Get-Item /home/ram).CreateSubdirectory('test-directory')
151 | ```
152 |
153 | Use a .NET type accelerator to convert text to an object:
154 |
155 | ```powershell
156 | [datetime]'21 June 2018'
157 |
158 | # Verify if the text was indeed converted into an object
159 | [DateTime]'21 June 2018' | Get-Member
160 | ```
161 |
162 | Use PowerShell to convert the same string into a date object:
163 |
164 | ```powershell
165 | Get-Date '21 June 2018'
166 |
167 | # Pick just the Year property to verify the output is indeed an object
168 | (Get-Date '21 June 2018').Year
169 | ```
170 |
171 | Convert text in the form of comma-separated values, to a PowerShell custom object:
172 |
173 | ```powershell
174 | # Create a file from text
175 | @'
176 | WS,CPU,Id,SI,ProcessName
177 | 161226752,23.42,1914,1566,io.elementary.a
178 | 199598080,77.84,1050,1040,gnome-shell
179 | 216113152,0.67,19250,1566,atom
180 | 474685440,619.05,1568,1566,Xorg
181 | 1387864064,1890.29,15720,1566,firefox
182 | '@ | Out-File sample.csv
183 |
184 | # Read the contents of the CSV file
185 | Get-Content ./sample.csv
186 |
187 | # Import the file into PowerShell instead of just reading the content
188 | Import-Csv ./sample.csv
189 | ```
190 |
191 | Compare output of Bash and PowerShell; work with files within a directory:
192 |
193 | ```powershell
194 | # Use Linux commandline tools
195 | ls -l | awk '{print $6, $7, $8, $9}'
196 |
197 | # Identify the output object type
198 | ls -l | awk '{print $6, $7, $8, $9}' | Get-Member
199 |
200 | # Use PowerShell
201 | Get-ChildItem | select LastWriteTime, Name
202 |
203 | # Identify the output object type
204 | Get-ChildItem | select LastWriteTime, Name | Get-Member
205 | ```
206 |
207 | Work with aliases in PowerShell:
208 |
209 | ```powershell
210 | # List out all the available aliases
211 | Get-Alias
212 |
213 | # Get information on a specific alias
214 | Get-Alias gbp
215 |
216 | # Find all aliases for a certain cmdlet
217 | Get-Alias -Definition Get-ChildItem
218 | ```
219 |
220 | Create a custom alias:
221 |
222 | ```powershell
223 | New-Alias listdir Get-ChildItem
224 | ```
225 |
226 | Export aliases to a file for future use:
227 |
228 | ```powershell
229 | # As a CSV file to use with Import-Alias
230 | Export-Alias aliases.csv
231 |
232 | # As a script, if you do not want to use CSV
233 | Export-Alias aliases.ps1 -As Script
234 | ```
235 |
236 | Working with execution policies (Windows only for now):
237 |
238 | ```powershell
239 | # Find the execution policy in effect
240 | Get-ExecutionPolicy
241 |
242 | # List out all the execution policies set at different levels
243 | Get-ExecutionPolicy -List
244 |
245 | # Set an execution policy at the machine level
246 | Set-ExecutionPolicy Undefined -Scope LocalMachine
247 |
248 | # Set an execution policy at the user level
249 | Set-ExecutionPolicy RemoteSigned -Scope CurrentUser
250 | ```
--------------------------------------------------------------------------------
/cheatsheets/chapter-02.md:
--------------------------------------------------------------------------------
1 | # Preparing for Administration using PowerShell
2 |
3 | Install Visual Studio Code from the repository (Ubuntu):
4 |
5 | ```bash
6 | sudo apt install code
7 | ```
8 |
9 | To install Visual Studio Code using the `deb` package:
10 |
11 | ```bash
12 | sudo apt install install code_version_arch.deb
13 | ```
14 |
15 | List the variables in a new terminal session:
16 |
17 | ```powershell
18 | # When using a cmdlet
19 | Get-Variable
20 |
21 | # When using a PowerShell provider
22 | Set-Location Variable:
23 | Get-ChildItem .
24 | ```
25 |
26 | To silence error output in case of errors:
27 |
28 | ```powershell
29 | Set-Variable ErrorActionPreference SilentlyContinue
30 | ```
31 |
32 | Working with a PowerShell profile:
33 |
34 | ```powershell
35 | # Create the new profile
36 | New-Item $PROFILE -ItemType File -Force
37 |
38 | # Edit the new profile in Visual Studio Code
39 | code $PROFILE
40 |
41 | # Delete the profile
42 | Remove-Item $PROFILE
43 | ```
44 |
45 | Sample long-running line of PowerShell code, broken for readability:
46 |
47 | ```powershell
48 | Get-ChildItem /home/$env:USERNAME/Downloads |
49 | Where-Object {$_.LastWriteTime.Year -eq 2018} | Select-Object `
50 | Name, LastWriteTime
51 | ```
52 |
53 | Send command output to a file:
54 |
55 | ```powershell
56 | # The Linux way (which works on PowerShell)
57 | Get-Process > processes.txt
58 |
59 | # The PowerShell way
60 | Get-Process | Out-File processes.txt
61 | ```
62 |
63 | Append output to a file:
64 |
65 | ```powershell
66 | # The Linux way (which works in PowerShell)
67 | Get-Process >> processes.txt
68 |
69 | # The PowerShell way
70 | Get-Process | Out-File processes.txt -Append
71 | ```
72 |
73 | To display the output on the terminal emulator as well as send it to a file:
74 |
75 | ```powershell
76 | # Only the PowerShell way
77 | Get-Process | Tee-Object ./processes.txt
78 | ```
79 |
80 | Reading content from a file:
81 |
82 | ```bash
83 | # The Linux way (which DOES NOT work on PowerShell)
84 | command < input.txt
85 | ```
86 |
87 | ```powershell
88 | # The PowerShell way
89 | Get-Content input.txt | Remove-Item -WhatIf
90 | ```
91 |
92 | Create new files/directories:
93 |
94 | ```powershell
95 | # Create a new directory
96 | New-Item -Path test-dir -ItemType Directory
97 |
98 | # Create a complete path instead (directory inside a directory)
99 | New-Item test-dir/child-dir -ItemType Directory -Force
100 |
101 | # Create multiple files
102 | New-Item ./test-dir/file1, ./test-dir/file2, ./test-dir/child-dir/file3
103 | ```
104 |
105 | Find parameter aliases:
106 |
107 | ```PowerShell
108 | (Get-Command Invoke-Command).Parameters.Values | select Name, Aliases
109 | ```
110 |
111 | Call PowerShell scripts from outside of PowerShell
112 |
113 | ```PowerShell
114 | # When the path to the script does not contain spaces
115 | /path/to/the-script.ps1
116 |
117 | # When the path to the script file contains a space
118 | & '/path/to/directory with spaces/script.ps1'
119 |
120 | # When we want the variables, aliases and functions retained in the session
121 | . /path/to/the-script.ps1
122 |
123 | # If there are spaces in the path, enclose it in quotes
124 | . '/path/to/directory with spaces/script.ps1'
125 | ```
126 |
127 | Call a PowerShell cmdlet from outside of PowerShell
128 |
129 | ```bash
130 | # When calling a cmdlet
131 | pwsh -c Get-ChildItem
132 |
133 | # When calling a script
134 | pwsh -f ./Documents/code/github/powershell/chapter-3/hello-world.ps1
135 | ```
136 |
137 | Record actions performed at the PowerShell console
138 |
139 | ```powershell
140 | # Start the recording
141 | Start-Transcript -Path ./command-transcript.txt
142 |
143 | # Perform actions on the terminal
144 | Get-Date
145 |
146 | Get-ChildItem .
147 |
148 | New-Item test-transcript -ItemType Directory
149 |
150 | New-Item -Path test-transcript/testing-transcript.txt -ItemType File
151 |
152 | # Add contents to the newly-created file
153 | @'
154 | In publishing and graphic design, lorem ipsum is a placeholder text
155 | commonly used to demonstrate the visual form of a document without relying
156 | on meaningful content (also called greeking).
157 | Replacing the actual content with placeholder text allows designers to
158 | design the form of the content before the content itself has been produced.
159 | —Wikipedia
160 | '@ | Out-File ./test-transcript/testing-transcript.txt -Append
161 |
162 | Remove-Item -Path ./test-transcript -Recurse
163 |
164 | # Stop the recording
165 | Stop-Transcript
166 |
167 | # Read the contents of the recording
168 | Get-Content -Path ./command-transcript.txt
169 | ```
--------------------------------------------------------------------------------
/cheatsheets/chapter-03.md:
--------------------------------------------------------------------------------
1 | # First steps to administration using PowerShell
2 |
3 | ## Working with date and time
4 |
5 | Custom formatting dates:
6 |
7 | ```PowerShell
8 | $Date = Get-Date
9 | "$($Date.Day)/$($Date.Month)/$($Date.Year)"
10 | ```
11 |
12 | Pre-formatted dates (some examples):
13 |
14 | ```PowerShell
15 | Get-Date -Format d
16 | Get-Date -Format g
17 | Get-Date -Format U
18 | Get-Date -Format yyyy/MM/dd
19 | Get-Date -Format yyyyMMddhhmmss
20 | ```
21 |
22 | UNIX-like date formatting:
23 |
24 | ```PowerShell
25 | Get-Date -Uformat %d/%m/%Y
26 | ```
27 |
28 | Find what day of week a certain date is:
29 |
30 | ```PowerShell
31 | # Avoiding all confusion
32 | (Get-Date -Day 31 -Month 10 -Year 2018).DayOfWeek
33 |
34 | # If your locale is the only context your scripts would run in
35 | (Get-Date 31/10/2018).DayOfWeek
36 |
37 | # Using a type accelerator
38 | ([datetime]'10/31/2018').DayOfWeek
39 |
40 | # Using a type accelerator, avoiding ambiguity
41 | ([datetime]'31 October 2018').DayOfWeek
42 | ```
43 |
44 | Convert time into UTC:
45 |
46 | ```PowerShell
47 | (Get-Date).ToUniversalTime()
48 | ```
49 |
50 | Calculating time:
51 |
52 | ```PowerShell
53 | # Add days to the current date
54 | (Get-Date).AddDays(35)
55 |
56 | # Subtract days from the current date
57 | (Get-Date).AddDays(-21)
58 |
59 | # Add hours and minutes
60 | (Get-Date).AddHours(3).AddMinutes(18)
61 |
62 | # Time between two dates
63 | (Get-Date).Subtract((Get-Date '5 June 2016'))
64 | ```
65 |
66 | ## Working with processes
67 |
68 | Working with currently running processes:
69 |
70 | ```PowerShell
71 | # Listing out the processes
72 | Get-Process
73 |
74 | # Counting the processes
75 | (Get-Process).Count
76 | ```
77 |
78 | Getting the average of memory pages used:
79 |
80 | ```PowerShell
81 | Get-Process | Measure-Object -Property WS -Average
82 | ```
83 |
84 | Getting more working set information:
85 |
86 | ```PowerShell
87 | Get-Process | Measure-Object -Property WS -Average -Sum -Minimum -
88 | Maximum
89 | ```
90 |
91 | Getting more than one such properties from the process table:
92 |
93 | ```PowerShell
94 | Get-Process | Measure-Object -Property WS, CPU -Average -Sum -Minimum -
95 | Maximum
96 | ```
97 |
98 | Getting the owner of processes:
99 |
100 | ```PowerShell
101 | Get-Process -IncludeUserName
102 | ```
103 |
104 | Listing the processes owned by you:
105 |
106 | ```PowerShell
107 | # Listing the processes
108 | Get-Process -IncludeUserName | grep $env:USERNAME
109 |
110 | # Counting the processes
111 | (Get-Process -IncludeUserName | grep $env:USERNAME).Count
112 |
113 | # Alternatively,
114 | Get-Process -IncludeUserName | grep $env:USERNAME | Measure-Object
115 | ```
116 |
117 | Bonus: Measuring the working set consumed by the processes owned by you (combination of PowerShell and Linux commands):
118 |
119 | ```PowerShell
120 | Get-Process -IncludeUserName | grep ram | awk '{print $1}' | ForEachObject
121 | {[Double]$_} | Measure-Object -Sum
122 | ```
123 |
124 | ## Scheduling jobs
125 |
126 | Creating a job that runs every fifteen minutes:
127 |
128 | ```PowerShell
129 | # Explicit configuration
130 | New-CronJob -Command 'pwsh -f "/tmp/DataLoading.PS1;"' -Minute
131 | 0,15,30,45 | Out-Host
132 |
133 | # Using interval notation
134 | New-CronJob -Command 'pwsh -f "/tmp/DataLoading.PS1;"' -Minute */15 |
135 | Out-Host
136 |
137 | # Specifying a time range
138 | New-CronJob -Command 'pwsh -f "/tmp/DataLoading.PS1;"' -Minute */15 -Hour 10-12 | Out-Host
139 |
140 | # With days of week and months of the year
141 | New-CronJob -Command 'pwsh -f "/tmp/DataLoading.PS1;"' -Minute */15 -
142 | Hour 10-12 -DayOfWeek sun, tue, fri -Month Jan, Mar, Jun, Sep, Dec | Out-Host
143 | ```
144 |
145 | Listing out scheduled jobs:
146 |
147 | ```PowerShell
148 | Get-CronJob
149 |
150 | # If you want better formatting:
151 | Get-CronJob | Format-Table -Autosize
152 | ```
153 |
154 | Get the contents of the `crontab` file:
155 |
156 | ```PowerShell
157 | Get-CronTab
158 | ```
159 |
160 | Removing jobs:
161 |
162 | ```PowerShell
163 | Get-CronJob | Where-Object {$_.Month -match 'Jan'} | Remove-CronJob
164 | ```
165 |
--------------------------------------------------------------------------------
/cheatsheets/chapter-04.md:
--------------------------------------------------------------------------------
1 | # Passing Data through the Pipeline
2 |
3 | Clone the [repository from GitHub](https://github.com/PacktPublishing/PowerShell-6.0-Linux-Administration-Cookbook) or download the [lab setup script](https://github.com/PacktPublishing/PowerShell-6.0-Linux-Administration-Cookbook/blob/master/ch04/Initialize-PacktPs6CoreLinuxLab.ps1) from the repository.
4 |
5 | Run the script to create the files for the lab.
6 |
7 | ```powershell
8 | & ~/Downloads/Initialize-PacktPs6CoreLinuxLab.ps1
9 | ```
10 |
11 | List out the contents of a directory:
12 |
13 | ```powershell
14 | Get-ChildItem -Path .
15 | ```
16 |
17 | Omit the `Mode` column from the output:
18 |
19 | ```powershell
20 | Get-ChildItem -Path . | Select-Object LastWriteTime, Length, Name
21 | ```
22 |
23 | Change the name of a column:
24 |
25 | ```powershell
26 | Get-ChildItem -Path . | Select-Object Name, Length, @{Name='Modified'; Expression={$_.LastWriteTime}}
27 | ```
28 |
29 | Pick only the year of modification using thecalculated property notation:
30 |
31 | ```powershell
32 | Get-ChildItem -Path . | select Name, Length, @{Name='DaysSinceModification'; Expression={[math]::Round(((Get-Date) - $_.LastWriteTime).TotalDays)}}
33 | ```
34 |
35 | Pick a certain number of ourput items:
36 |
37 | ```powershell
38 | # First five items
39 | Get-ChildItem . | Select-Object -First 5
40 |
41 | # Last five items
42 | Get-ChildItem . | Select-Object -Last 5
43 |
44 | # Skip the first three items
45 | Get-ChildItem . | Select-Object -Skip 3
46 |
47 | # Pick the fourth item from the output
48 | Get-ChildItem . | Select-Object -Index 3
49 | ```
50 |
51 | Expand the elements within a property:
52 |
53 | ```powershell
54 | # The pwsh process
55 | Get-Process pwsh | Select-Object -ExpandProperty Threads
56 |
57 | # Select specific properties from within the property
58 | Get-Process pwsh | Select-Object -ExpandProperty Threads | Select-Object -Property Id, PriorityLevel, StartTime
59 | ```
60 |
61 | Filter out files that are over 0 bytes in size:
62 |
63 | ```powershell
64 | Get-ChildItem -Path . | Where-Object -Property Length -GT -Value 0
65 | ```
66 |
67 | Filter based on two (or more) properties:
68 |
69 | ```powershell
70 | # Pick all the JPG files larger than 0 bytes
71 | Get-ChildItem -Path . | Where-Object -FilterScript {$_.Length -GT 0 -and $_.Extension -EQ '.jpg'}
72 |
73 | # Pick files as above, whose names start with c
74 | Get-ChildItem -Path . | Where-Object -FilterScript {$_.Length -GT 0 -and $_.Extension -EQ '.jpg' -and $_.Name -CMatch '^c'}
75 | ```
76 |
77 | Group output based on a property:
78 |
79 | ```powershell
80 | Get-ChildItem . -File | Group-Object Extension
81 |
82 | # Do the same, but do not show the file names
83 | Get-ChildItem -Path . -File | Group-Object -Property Extension -NoElement
84 |
85 | # Show only the JPG files from the lot
86 | Get-ChildItem -Path . -File | Group-Object -Property Extension | Where-Object Name -EQ .jpg | Select-Object -ExpandProperty Group
87 | ```
88 |
89 | Sort the output based on a property:
90 |
91 | ```powershell
92 | Get-ChildItem -Path . -File | Sort-Object -Property Length
93 |
94 | # Sort in the descending order
95 | Get-ChildItem -Path . -File | Sort-Object -Property Length -Descending
96 |
97 | # Pick the largest three files in the lot
98 | Get-ChildItem -Path . -File | Sort-Object -Property Length -Descending -Top 3
99 | ```
100 |
101 | (Dummy-)delete top two largest files of each type from a directory (if there is only one file of each type, that would be left alone):
102 |
103 | ```powershell
104 | Get-ChildItem -Path . -File |
105 | Group-Object -Property Extension |
106 | Where-Object Count -GT 1 |
107 | ForEach-Object {$_.Group |
108 | Sort-Object Length -Bottom 2} |
109 | Remove-Item -WhatIf
110 | ```
111 |
112 | The long way to get directory contents, which demonstrates accepting values through the pipeline, `ByPropertyName`:
113 |
114 | ```powershell
115 | Get-Item . | Select-Object @{Name = 'LiteralPath'; Expression = {$_.FullName}} | Get-ChildItem
116 | ```
117 |
118 | Import content into PowerShell and work with the object:
119 |
120 | ```powershell
121 | # First export the content so we have some real data
122 | Get-ChildItem -Path . | Select-Object Name, FullName, CreationTime, LastWriteTime, Extension, Length | Export-Csv ./file-list.csv
123 |
124 | # Import the content and get the year when the files were created; what type of object is it?
125 | (Import-Csv ./file-list.csv).CreationTime.Year | Get-Member
126 |
127 | # Export the content with the object type intact
128 | Get-ChildItem -Path . | Export-Clixml ./file-list.xml
129 |
130 | # Import the content and get the year when the files were created; what type of object is it?
131 | (Import-Clixml ./file-list.xml).CreationTime.Year | Get-Member
132 | ```
--------------------------------------------------------------------------------
/cheatsheets/chapter-05.md:
--------------------------------------------------------------------------------
1 | # Using Variables and Objects
2 |
3 | Save an entire object into a variable:
4 |
5 | ```powershell
6 | $Process = Get-Process
7 | ```
8 |
9 | Work with environment variables:
10 |
11 | ```powershell
12 | # List out all the environment variables
13 | Get-ChildItem env:
14 |
15 | # Get information on a specific variable
16 | Get-ChildItem Env:/PATH
17 | ```
18 |
19 | Quickly create a custom object:
20 |
21 | ```powershell
22 | $MyCustomObject = [pscustomobject]@{
23 | Name = 'Prashanth Jayaram'
24 | Title = 'PowerShell'
25 | Publisher = 'Packt'
26 | }
27 | ```
28 |
29 | Add a member to an existing object:
30 |
31 | ```powershell
32 | $MyCustomObject | Add-Member -MemberType NoteProperty -Name 'Location' -Value 'United States'
33 | ```
34 |
35 | Access a single property from the object:
36 |
37 | ```powershell
38 | $MyCustomObject.Name
39 | ```
40 |
41 | Remove a member from an object:
42 |
43 | ```powershell
44 | $MyCustomObject.PsObject.Properties.Remove('Location')
45 | ```
46 |
47 | Create a custom object from an output object:
48 |
49 | ```powershell
50 | # Assign an object to a variable
51 | $Process = (Get-Process | Select-Object Name, Id, WS, StartTime)[4]
52 |
53 | # Create a new object
54 | $CustomProcess = New-Object -TypeName PSObject -Property @{
55 | ProcessName = $Process.Name
56 | ProcessId = $Process.Id
57 | WorkingSet = $Process.WS
58 | StartedAt = $Process.StartTime
59 | }
60 |
61 | # To have the object properties in a certain sequence
62 | $CustomProcess = [ordered]@{
63 | ProcessName = $Process.Name
64 | ProcessId = $Process.Id
65 | WorkingSet = $Process.WS
66 | StartedAt = $Process.StartTime
67 | }
68 | New-Object -TypeName PSObject -Property $CustomProcess
69 |
70 | # Modify the properties and their values to suit your needs
71 | $CustomProcess = [ordered]@{
72 | ProcessName = $Process.Name
73 | ProcessId = $Process.Id
74 | WorkingSet = $Process.WS
75 | RunningMins = [math]::Floor(((Get-Date) - $Process.StartTime).TotalMinutes)
76 | }
77 | New-Object -TypeName PsObject -Property $CustomProcess
78 | ```
79 |
80 | Add members to objects without recreating the entire object:
81 |
82 | ```powershell
83 | # Get the base object
84 | $FilesWithAge = Get-ChildItem . | Select-Object Name, Length, LastWriteTime
85 |
86 | # Add a member to the object
87 | $FilesWithAge | Add-Member -MemberType ScriptProperty -Name Age -Value { [math]::Round(((Get-Date) - $this.LastWriteTime).TotalDays) }
88 | ```
89 |
90 | Update the type data using cmdlets:
91 |
92 | ```powershell
93 | Update-TypeData -TypeName System.IO.FileInfo -MemberType ScriptProperty -MemberName Age -Value { [math]::Round(((Get-Date) - $this.LastWriteTime).TotalDays) }
94 | ```
95 |
96 | Basic structure of the XML used to extend the type data:
97 |
98 | ```xml
99 |
100 |
101 |
102 |
103 |
104 |
105 |
106 |
107 |
108 |
109 |
110 |
111 | ```
112 |
113 | Break down the XML to understand the different kinds of properties:
114 |
115 | ```xml
116 |
117 |
118 | Modified
119 | LastWriteTime
120 |
121 |
122 |
123 |
124 | Age
125 |
126 | [math]::Round(((Get-Date) - $this.LastWriteTime).TotalDays)
127 |
128 |
129 |
130 |
131 |
132 | ItemType
133 | File
134 |
135 | ```
136 |
137 | Extend the type data using an XML file:
138 |
139 | ```powershell
140 | Update-TypeData -PrependPath '~/Documents/code/github/powershell/ch05/CustomTypes.ps1xml'
141 | ```
142 |
143 | Remove custom type data:
144 |
145 | ```powershell
146 | # Start with the command that gives you the object whose type data you extended
147 | $TypeData = Get-ChildItem -File | Get-Member | Select-Object -ExpandProperty TypeName -Unique
148 |
149 | # Ensure there has been a type data extension; notice the members
150 | Get-TypeData -TypeName $TypeData | Select-Object -ExpandProperty Members
151 |
152 | # Remove the custom type data
153 | Remove-TypeData -TypeName $TypeData
154 | ```
--------------------------------------------------------------------------------
/cheatsheets/chapter-06.md:
--------------------------------------------------------------------------------
1 | # Working with Strings
2 |
3 | This cheatcheet is divided into two parts:
4 |
5 | 1. *Operators in PowerShell*, which is directly referred to in the chatpter.
6 | 2. *String operations in PowerShell*, which is, well, the usual cheatsheet.
7 |
8 | ## Operators in PowerShell
9 |
10 | Enter the following at the prompt.
11 |
12 | ```powershell
13 | (((2 * -5) / 10 + 16 ) % 4) - (-7)
14 | ```
15 |
16 | Assign this to a variable that already contains a value. First, assign $Number a value of 25.
17 |
18 | ```powershell
19 | $Number = 25
20 |
21 | $Number += (((2 * -5) / 10 + 16 ) % 4) - (-7)
22 |
23 | $Number
24 | ```
25 |
26 | Increment $Number and show its value.
27 |
28 | ```powershell
29 | $Number++
30 |
31 | $Number
32 | ```
33 |
34 | Perform a few comparisons.
35 |
36 | ```powershell
37 | $Number -gt -5
38 |
39 | $Number -ge 36
40 |
41 | $Number -ne 36
42 |
43 | 'c' -gt 'k'
44 | ```
45 |
46 | See if a certain string pattern matches another.
47 |
48 | ```powershell
49 | 'Frodo' -clike '?rod?'
50 |
51 | 'Frodo' -cmatch '^[^A-Z]'
52 |
53 | 'Frodo' -match 'frodo'
54 | ```
55 |
56 | Try a few logical operators.
57 |
58 | ```powershell
59 | $true -or $false
60 |
61 | 1 -and 0
62 |
63 | 1 -and 1
64 | ```
65 |
66 | Split and join a few strings.
67 |
68 | ```powershell
69 | 'The quick brown fox jumps over the lazy dog' -split ' '
70 | ```
71 |
72 | Join the resulting set of words using a comma and a space.
73 |
74 | ```powershell
75 | ('The quick brown fox jumps over the lazy dog' -split ' ') -join ', '
76 | ```
77 |
78 | See if the resulting series of characters is a string.
79 |
80 | ```powershell
81 | ('The quick brown fox jumps over the lazy dog' -split ' ') -join ', ' -is [string]
82 | ```
83 |
84 | Convert a double into an integer.
85 |
86 | ```powershell
87 | 2.21 -as [int]
88 | ```
89 |
90 | Go back to the pangram we split into separate words. Assign the values to a variable, one after another.
91 |
92 | ```powershell
93 | 'The quick brown fox jumps over the lazy dog' -split ' ' | ForEach-Object { $Pangram += $PSItem }
94 |
95 | $Pangram
96 | ```
97 |
98 | That was not what we wanted. We want this to be an array of strings.
99 |
100 | ```powershell
101 | Remove-Variable Pangram
102 |
103 | $Pangram = @()
104 |
105 | 'The quick brown fox jumps over the lazy dog' -split ' ' | ForEach-Object { $Pangram += $PSItem }
106 |
107 | $Pangram
108 | ```
109 |
110 | Now, try the same thing with the comma operator.
111 |
112 | ```powershell
113 | Remove-Variable $Pangram
114 |
115 | 'The quick brown fox jumps over the lazy dog' -split ' ' | ForEach-Object { $Pangram += , $PSItem }
116 |
117 | $Pangram
118 | ```
119 |
120 | Pick the eighth word from the array because it describes me.
121 |
122 | ```powershell
123 | $Pangram[7]
124 | ```
125 |
126 | Also:
127 |
128 | ```powershell
129 | $Pangram -contains 'fox'
130 | ```
131 |
132 | Recall Recipe 4.1: Working with date properties, wherein we showed the date in a proper format.
133 |
134 | ```powershell
135 | "Six hours from now would be $((Get-Date).AddHours(6))."
136 | ```
137 |
138 | Cast a date as a DateTime object and use the member access operator to call the ToShortDateString method.
139 |
140 | ```powershell
141 | ([datetime]'13 July 2018').ToShortDateString()
142 | ```
143 |
144 | Finally, set the variable, $Numbers with values ranging from 91 to 100.
145 |
146 | ```powershell
147 | $Numbers = 91..100
148 |
149 | $Numbers
150 | ```
151 |
152 | Oh, you thought that initialising a variable, splitting a pangram, and then using a loop to add the elements to the empty variable was an overkill, too? PowerShell isn't complicated; it is friendly. That longer path was to help you understand how strings and string arrays work. Here is an easier way to add the split elements to the array:
153 |
154 | ```powershell
155 | Remove-Variable Pangram
156 | $Pangram = 'The quick brown fox jumps over the lazy dog' -split ' '
157 | ```
158 |
159 | ## Different types of strings in PowerShell
160 |
161 | To create a literal string:
162 |
163 | ```powershell
164 | # Use single quotes
165 | 'This is a literal string'
166 |
167 | # If the string contains a single quote
168 | 'I''m a literal string'
169 |
170 | # Try a line break
171 | 'I''m a literal string`nI like showing up on the screen.'
172 | ```
173 |
174 | To create an expanding string:
175 |
176 | ```powershell
177 | # Expanding strings expand the variables within
178 | "My home directory is $HOME"
179 |
180 | # When a double quote appears within an expanding string
181 | "Here is an ""expanding string"" with a double quote"
182 |
183 | # Alternatively
184 | "Here is an `"expanding string`" with a double quote"
185 |
186 | # Try a line break; we know that escape characters work
187 | "I'm an expanding string`nI like showing up on the screen."
188 | ```
189 |
190 | Here Strings are strings that respect formatting.
191 |
192 | ```powershell
193 | # A literal Here String
194 | @'
195 | Hello, there!
196 |
197 | I am a Here String. PowerShell respects the way I look.
198 |
199 | This Here String is the literal type. Therefore, $HOME appears as it is.
200 | '@
201 |
202 | # An expanding Here String
203 | @"
204 | Hello, there!
205 |
206 | I am a Here String. PowerShell respects the way I look.
207 |
208 | This Here String is the expanding type. Therefore, $HOME is expanded to its value.
209 | "@
210 | ```
211 |
212 | ## String methods
213 |
214 | These are methods within the `System.String` object.
215 |
216 | Let us first look at trimming
217 |
218 | ```powershell
219 | # Let us say we have a string assigned to a variable
220 | $String = '.This is a string with a period on both the ends.'
221 |
222 | # To trim a certain character in the beginning of a string
223 | $String.TrimStart('.')
224 |
225 | # To trim a certain character at the end of a string
226 | $String.TrimEnd('.')
227 |
228 | # To trim a certain character from the beginning and the end of the string
229 | $String.Trim('.')
230 | ```
231 |
232 | Next, work with string arrays. First, let us split the current string for use as an example.
233 |
234 | ```powershell
235 | $String = $String.TrimStart('.')
236 |
237 | # Split the string into an array
238 | $String = $String.Split(' ')
239 |
240 | # Now to get the fourth word from the sentence
241 | $String[3]
242 |
243 | # To get the index of a certain character
244 | $String[3].IndexOf('i')
245 |
246 | # To get a substring starting at 'i'
247 | $String[3].Substring($String[3].IndexOf('i'))
248 | ```
249 |
250 | There are some string functions to change the case of strings as well
251 |
252 | ```powershell
253 | # To convert the case of the entire string to uppercase
254 | $String[4].ToUpper()
255 | ```
256 |
257 | String replacement works using string methods as well
258 |
259 | ```powershell
260 | $String[4].Replace('i', 'o')
261 | ```
262 |
263 | ## String operations using operators
264 |
265 | To see whether an array contains a certain element, use the `contains` operator.
266 |
267 | ```powershell
268 | $String -contains 'string'
269 | ```
270 |
271 | To see if a certain string contains a pattern:
272 |
273 | ```powershell
274 | $String[6] -like '*io*'
275 |
276 | # Alternatively
277 | $String[6] -match 'io'
278 | ```
279 |
280 | To replace a string using an operator instead of a string method:
281 |
282 | ```powershell
283 | $String[4] -replace 'i', 'o'
284 | ```
285 |
286 | To learn to leverage regex for more complex string matching operations, refer to the recipe, _Replacing substrings within strings_.
287 |
288 | To combine a string, use the `join` operator:
289 |
290 | ```powershell
291 | # Join all the words in the $String array using a space
292 | $String = $String -join ' '
293 | ```
294 |
295 | To split the string, use the `split` operator:
296 |
297 | ```powershell
298 | # Split the sentence again at spaces
299 | $String = $String -split ' '
300 | ```
301 |
302 | ## Formatting strings
303 |
304 | You can use the formatting operator to format strings. Let us continue using the `$String` array.
305 |
306 | ```powershell
307 | # To say 'This string contains a period', string and period being elements of the array
308 | "This {0} contains a {1}." -f $String[3], $String[6]
309 | ```
310 |
311 | To add a currency to the formatted output
312 |
313 | ```powershell
314 | "{0:c}" -f 56
315 | ```
316 |
317 | To format a number a certain way
318 |
319 | ```powershell
320 | "{0:####-####-####-####}" -f 9089878728592950
321 | ```
322 |
323 | To right-align an entire string array:
324 |
325 | ```powershell
326 | "{0,6}`n{1,6}`n{2,6}`n{3,6}" -f $String
327 | ```
--------------------------------------------------------------------------------
/cheatsheets/chapter-07.md:
--------------------------------------------------------------------------------
1 | # Flow Control using Branches and Loops
2 |
3 | Branching and looping are perhaps at the heart of any kind of logical flow.
4 |
5 | ## Branching
6 |
7 | The most basic kind of branching is the `if` statement:
8 |
9 | ```powershell
10 | $Today = Get-Date
11 |
12 | if ($Today.DayOfWeek -eq 'Sunday') {
13 | "Don't disturb me."
14 | }
15 | ```
16 |
17 | If you have two conditions and they are mutually exclusive:
18 |
19 | ```powershell
20 | $Today = Get-Date
21 |
22 | if ($Today.DayOfWeek -eq 'Sunday') {
23 | "Don't disturb me."
24 | }
25 | else {
26 | "I'm available."
27 | }
28 | ```
29 |
30 | If you have more conditions:
31 |
32 | ```powershell
33 | $Today = Get-Date
34 |
35 | if ($Today.DayOfWeek -eq 'Sunday') {
36 | "Don't disturb me."
37 | }
38 | elseif ($Today.DayOfWeek -eq 'Saturday') {
39 | "I'm available for parties."
40 | }
41 | else {
42 | "I'm available to work."
43 | }
44 | ```
45 |
46 | If you have more (and specific conditions), use the switch–case statement:
47 |
48 | ```powershell
49 | $Today = (Get-Date).DayOfWeek
50 |
51 | switch ($Today) {
52 | 'Saturday' {
53 | "I'm available for parties."
54 | }
55 | 'Sunday' {
56 | "Don't disturb me."
57 | }
58 | }
59 | ```
60 |
61 | If you need a catch-all:
62 |
63 | ```powershell
64 | $Today = (Get-Date).DayOfWeek
65 |
66 | switch ($Today) {
67 | 'Saturday' {
68 | "I'm available for parties."
69 | }
70 | 'Sunday' {
71 | "Don't disturb me."
72 | }
73 | Default {
74 | "I'm available to work."
75 | }
76 | }
77 | ```
78 |
79 | If you would like wildcard matching:
80 |
81 | ```powershell
82 | $Today = (Get-Date).DayOfWeek
83 |
84 | switch -wildcard ($Today) {
85 | 'S*day' {
86 | "Weekend!"
87 | }
88 | Default {
89 | "Weekday."
90 | }
91 | }
92 | ```
93 |
94 | ## Looping
95 |
96 | There are six looping constructs in PowerShell.
97 |
98 | The first one is a cmdlet, that works through the pipeline:
99 |
100 | ```powershell
101 | $String = 'This is a string with a period.' -split ' '
102 |
103 | $String | Foreach-Object {$PSItem.ToUpper()} # Of course, you can do $String.ToUpper(), but play along.
104 | ```
105 |
106 | Next, when you don't want to use the pipeline, but have a finite set of objects as an array:
107 |
108 | ```powershell
109 | $String = 'This is a string with a period.' -split ' '
110 |
111 | foreach ($Element in $String) {
112 | $Element.ToUpper()
113 | }
114 | ```
115 |
116 | Now to the looping constructs most of us are familiar with from other languages:
117 |
118 | First is the For loop.
119 |
120 | ```powershell
121 | for ($i = 0; $i -lt 10; $i++) {
122 | $i
123 | }
124 | ```
125 |
126 | If you want a while construct:
127 |
128 | ```powershell
129 | $i = 0
130 | while ($i -lt 10) {
131 | $i
132 | $i++
133 | }
134 | ```
135 |
136 | If you want the loop to execute once regardless of whether the condition is met:
137 |
138 | ```powershell
139 | $i = 11
140 | do {
141 | $i
142 | $i++
143 | } while ($i -lt 10)
144 | "The current value of i after the loop is $i"
145 | ```
146 |
147 | That loop exited when the condition became false. If you would like the loop to exit when the condition became true (and execute it once regardless of whether the outcome of the condition is true or false):
148 |
149 | ```powershell
150 | $i = 11
151 | do {
152 | $i
153 | $i++
154 | } until ($i -gt 10)
155 | "The current value of i after the loop is $i"
156 | ```
--------------------------------------------------------------------------------
/cheatsheets/chapter-08.md:
--------------------------------------------------------------------------------
1 | # Performing Calculations
2 |
3 | Calculations in PowerShell are rather simple.
4 |
5 | ## Arithmetic operations
6 |
7 | The basic math:
8 |
9 | ```powershell
10 | 5 + 25 / 5 * 21 % (10 - 5)
11 | ```
12 |
13 | Using math accelerators:
14 |
15 | ```powershell
16 | # To get the square of a number
17 | [math]::Pow(5, 2)
18 |
19 | # To get the square root of a number
20 | [math]::Sqrt(25)
21 |
22 | # The floor and the ceiling functions
23 | [math]::Ceiling(32.223)
24 | [math]::Floor(32.223)
25 |
26 | # To round off a number to the nearest hundredth
27 | [math]::Round(32.223, 2)
28 | ```
29 |
30 | There are administrative constants in PowerShell that help you convert numbers:
31 |
32 | ```powershell
33 | # To convert bytes into MB
34 | 1099511627776/1MB
35 |
36 | # To convert bytes into GB
37 | 1099511627776/1GB
38 |
39 | # To convert bytes into TB
40 | 1099511627776/1TB
41 |
42 | # To get multiples of 10
43 | 8 * 1e3
44 | ```
45 |
46 | Type conversion is also simple in PowerShell:
47 |
48 | ```powershell
49 | # To convert hexadecimal into integer
50 | [int]("0x222")
51 |
52 | # To convert an integer into an Octal number
53 | [Convert]::ToString('565', 8)
54 |
55 | # To convert an integer into a hexadecimal number
56 | [Convert]::ToString('565', 16)
57 |
58 | # To convert an integer into a binary number
59 | [Convert]::ToString('565', 2)
60 | ```
--------------------------------------------------------------------------------
/cheatsheets/chapter-09.md:
--------------------------------------------------------------------------------
1 | # Using Arrays and Hashtables
2 |
3 | Remember them like this: Arrays are collections of elements; use indices to address them. Hashtables are arrays that use names to address the elements.
4 |
5 | ## Arrays
6 |
7 | There are two ways to create an array:
8 |
9 | ```powershell
10 | # First, by initializing an array and adding contents
11 | $Array = @()
12 |
13 | $Array += 'First element'
14 | $Array += 'Second element'
15 |
16 | # Second, using the comma operator
17 | $Array = , 'First element' + 'Second element'
18 | ```
19 |
20 | To combine arrays, simply add them:
21 |
22 | ```powershell
23 | $ArrayOne = , 'First element' + 'Second element'
24 | $ArrayTwo = , 'Third element' + 'Fourth element'
25 |
26 | $ArrayOne + $ArrayTwo
27 | ```
28 |
29 | To create a jagged array:
30 |
31 | ```powershell
32 | $JaggedArray = @(
33 | (1, 2, 3, 4, 5),
34 | (6, 7, 8),
35 | (9, 10, 11, 12, 13, 14),
36 | (15, 16, 17, 18),
37 | (19, 20)
38 | )
39 | ```
40 |
41 | To create a non-jagged array:
42 |
43 | ```powershell
44 | $MultiDimensionalArray = New-Object -TypeName "int[,]" 4, 5
45 | $Count = 1
46 | for ([int]$i = 0; $i -lt 4; $i++) {
47 | for ([int]$j = 0; $j -lt 5; $j++) {
48 | $MultiDimensionalArray[$i,$j] = $Count
49 | $Count++
50 | }
51 | }
52 |
53 | # Access a random member from within the array:
54 | $MultiDimensionalArray[2,3]
55 | ```
56 |
57 | To access an element from the array, use the index:
58 |
59 | ```powershell
60 | $Array = , 'First element' + 'Second element'
61 |
62 | $Array[1]
63 | ```
64 |
65 | To see if an array contains an element:
66 |
67 | ```powershell
68 | $Array -contains 'Second element'
69 | ```
70 |
71 | To match patterns in an array:
72 |
73 | ```powershell
74 | $Array -match 'element'
75 |
76 | $Array -match 'First'
77 | ```
78 |
79 | To remove an element from an array:
80 |
81 | ```powershell
82 | # Create a new object of type System.Collections.ArrayList
83 | $NewArray = New-Object -TypeName System.Collections.ArrayList
84 |
85 | # Use the Add() method of the object to add elements
86 | $NewArray.Add('First element')
87 | $NewArray.Add('Second element')
88 | $NewArray.Add('Third element')
89 |
90 | # To remove an element from the array, use the Remove() method from within the object
91 | $NewArray.Remove('Second element')
92 | ```
93 |
94 | The other way of removing objects from an array is to filter unwanted elements using `Where-Object` and then, assigning those values to a new variable.
95 |
96 | To compare two arrays, use the `Compare-Object` cmdlet.
97 |
98 | ```powershell
99 | $ArrayOne = , 'First element' + 'Second element' + 'Third element'
100 | $ArrayTwo = , 'Third element' + 'Fourth element' + 'Fifth element'
101 |
102 | Compare-Object -ReferenceObject $ArrayOne -DifferenceObject $ArrayTwo
103 | ```
104 |
105 | ## Hashtables
106 |
107 | To initialize a hashtable:
108 |
109 | ```powershell
110 | $MyHashtable = @{} # As opposed to @() for arrays
111 | ```
112 |
113 | To add elements to a hashtable:
114 |
115 | ```powershell
116 | $MyHashtable['FirstElement'] = 1
117 | $MyHashtable['SecondElement'] = 2
118 | ```
119 |
120 | To access the elements in a hashtable:
121 |
122 | ```powershell
123 | $MyHashtable['SecondElement']
124 | ```
125 |
126 | To see if the hashtable contains a certain element (find by name):
127 |
128 | ```powershell
129 | $MyHashtable.Contains['FirstElement']
130 | ```
131 |
132 | To remove an element from a hashtable:
133 |
134 | ```powershell
135 | $MyHashtable.Remove['SecondElement']
136 | ```
137 |
138 | You can also use a method to add elements to a hashtable:
139 |
140 | ```powershell
141 | $MyHashtable.Add('ThirdElement', 3)
142 | ```
143 |
144 | To sort a hashtable:
145 |
146 | ```powershell
147 | # Based on the names
148 | $MyHashtable.GetEnumerator() | Sort-Object Name
149 |
150 | # Based on the values
151 | $MyHashtable.GetEnumerator() | Sort-Object Value
152 | ```
--------------------------------------------------------------------------------
/cheatsheets/chapter-10.md:
--------------------------------------------------------------------------------
1 | # Handling Files and Directories
2 |
3 | To read contents from a file:
4 |
5 | ```powershell
6 | # To get everything within the file
7 | Get-Content './path/to/file.ext'
8 |
9 | # To get the first, say, 5 lines from the file, as a single block
10 | Get-Content './path/to/file.ext' -ReadCount 7 | Select-Object -First 1
11 |
12 | # To get the last, say, 5 lines of the file
13 | Get-Content './path/to/file.ext' -Tail 5
14 |
15 | # If you would like to keep the file open for reading, such as when reading logs at the terminal
16 | Get-Content './path/to/file.ext' -Tail 5 -Wait
17 |
18 | # To get, say, the eleventh to the thirteenth lines of the file
19 | Get-Content './path/to/file.ext' | Select-Object -Skip 10 -First 3
20 |
21 | # To measure the number of characters, words and lines in the file
22 | Get-Content './path/to/file.ext' | Measure-Object -Character -Word -Line
23 |
24 | # Get-Content imports contents line-by-line. Each line is a separate object. If you would like all the contents as a single block, use
25 | Get-Content './path/to/file.ext' -Raw
26 | ```
27 |
28 | To send output to a file
29 |
30 | ```powershell
31 | # Let us assume you want to send the current date to a file
32 |
33 |
34 | # Using an operator
35 | Get-Date > ./path/to/output-file.txt
36 |
37 | # Using a cmdlet
38 | Get-Date | Out-File ./path/to/output-file.txt
39 |
40 | # To send errors to a file (by "polluting" the Success stream)
41 | Get-Content ./nonexistent/path.ext 2>&1 | Out-File ./path/to/desired-file.txt
42 |
43 | # To send errors to a file (by not "polluting" the Success stream)
44 | Get-Content ./nonexistent/path.ext 2> ./path/to/desired-file.txt
45 |
46 | # To send output of Write-Host or Write-Information to a file (by "polluting" the Success stream)
47 | Write-Host "This is just a host message" 6>&1 | Out-File ./path/to/desired-file.txt
48 |
49 | # Alternative, using only redirection operators
50 | Write-Host "This is just a host message" 6>&1> ./path/to/desired-file.txt
51 |
52 | # To send output of Write-Host or Write-Information to a file (by not "polluting" the Success stream)
53 | Write-Host "This is just a host message" 6> ./path/to/desired-file.txt
54 |
55 | # To send contents to both, a file, as well as down the pipeline
56 | Get-Date | Tee-Object ./path/to/desired-file.txt
57 | # In this case, since no pipeline follows Tee-Object, the ouptut will appear on the host
58 | ```
59 |
60 | Here is a list of all the streams in PowerShell, in order:
61 |
62 | 1. Success stream
63 | 2. Error stream
64 | 3. Warning stream
65 | 4. Verbose stream
66 | 5. Debug stream
67 | 6. Information stream
68 |
69 | Today, the Information stream also handles content sent to the host. The host was not part of any stream until PowerShell 5.0.
70 |
71 | Only the contents of the Success stream go through the pipeline. Therefore, if the contents of any other stream are to be sent to through the pipeline, the content must be redirected to the Success stream first.
72 |
73 | To manipulate the contents of a file:
74 |
75 | ```powershell
76 | # To send contents to a file using an alternate method or replace the contents
77 | Set-Content './path/to/file.ext' "The content that you would like the file to have"
78 |
79 | # To add content to a file
80 | Add-Content './path/to/file.ext' "The content you would like to add to the file"
81 |
82 | # To clear contents of a file
83 | Clear-Content './path/to/file.ext'
84 | ```
85 |
86 | To search for a string in a file:
87 |
88 | ```powershell
89 | # A simple listing of all occurrences
90 | Select-String -Pattern 'MyPattern' -Path './path/to/file.ext'
91 |
92 | # To get the context of each of the occurrences (two lines before and after the occurrence)
93 | Select-String -Pattern 'MyPattern' -Path './path/to/file.ext' -Context 2, 2
94 |
95 | # To perform a search on multiple files excluding a few
96 | Select-String -Pattern 'MyPattern' -Path './path/to/*.ext' -Exclude '*ExclusionFilenamePattern*'
97 | ```
98 |
99 | To know where the script is running from (querying within the script, not outside)
100 |
101 | ```powershell
102 | $PsScriptRoot
103 | ```
104 |
105 | To know the complete path to the script that was run (querying within the script, not outside):
106 |
107 | ```powershell
108 | $PsCommandPath
109 | ```
110 |
111 | To create paths irrespective of the platform:
112 |
113 | ```powershell
114 | # Simple path join
115 | Join-Path -Path 'DesiredPath' -ChildPath 'DesiredChildPath'
116 |
117 | # Creating a single child path within multiple parent paths
118 | Join-Path /home, /etc, /var, /boot -ChildPath MyDir
119 |
120 | # Creating multiple child paths within a single parent path
121 | 'file1.txt', 'file2.txt', 'file3.txt' | ForEach-Object { Join-Path -Path $HOME/dir/ -ChildPath $PSItem }
122 | ```
123 |
124 | To search for the existence of paths with a certain pattern (using a wildcard)
125 |
126 | ```powershell
127 | # To simply resolve all the paths that match that pattern
128 | Resolve-Path /home/*/random
129 |
130 | # To split paths at the path separator
131 | Split-Path -Parent # Gives the path omitting the last location, `random` in this case
132 | Split-Path -Leaf # Shows the last location `random`, in this case
133 | ```
134 |
135 | To actually create files/directories at the paths you created using `Join-Path`
136 |
137 | ```powershell
138 | Join-Path dir-01, dir-02, dir-03, dir-04 -ChildPath demo.txt | ForEach-
139 | Object { New-Item $PSItem -ItemType File }
140 | ```
141 |
142 | To rename files/directories
143 |
144 | ```powershell
145 | Rename-Item -Path oldname.ext -NewName newname.ext
146 | ```
147 |
148 | To copy items from one point to another
149 |
150 | ```powershell
151 | Copy-Item -Path /path/to/file.ext -Destination ./destination/directory # This retains the file name
152 | ```
153 |
154 | To delete a file/directory
155 |
156 | ```powershell
157 | # To delete a file
158 | Remove-Item ./path/to/file.ext
159 |
160 | # To delete a directory that contains items within itself
161 | Remove-Item ./path/to/directory/ -Recurse
162 | # If `-Recurse` is not used, and PowerShell finds contents within the specified directory, it would prompt whether you would like to go with a recursive deletion
163 | ```
164 |
165 | To convert JSON into a PowerShell object:
166 |
167 | ```powershell
168 | ConvertFrom-Json 'JSON string here' # Yup, it's that simple
169 | ```
--------------------------------------------------------------------------------
/cheatsheets/chapter-11.md:
--------------------------------------------------------------------------------
1 | # Building Scripts and Functions
2 |
3 | When calling a script, the path to which contains a space (without actually retaining anything from the script, in the session)
4 |
5 | ```powershell
6 | & './path to/script.ps1'
7 | ```
8 |
9 | When the entities within the script (such as variables or functions) have to be retained in the session:
10 |
11 | ```powershell
12 | . './path to/script.ps1'
13 | ```
14 |
15 | To read content from the console:
16 |
17 | ```powershell
18 | Read-Host -Prompt "Enter prompt here"
19 | ```
20 |
21 | To display the progress of execution
22 |
23 | ```powershell
24 | $TerminatingCondition = 25 # (I'm counting to 25 seconds)
25 | $CurrentCondition = 0 # (You know this part now)
26 |
27 | do {
28 | Write-Progress -Activity 'Counting to 25' -Status "Elapsed time: $CurrentCondition seconds" -PercentComplete ($CurrentCondition / $TerminatingCondition * 100)
29 | Start-Sleep 1 # Because this should happen at a human speed
30 | $CurrentCondition++ # Because progress is everything
31 | } until ($CurrentCondition -eq $TerminatingCondition) # Why use the boring do-while?
32 | ```
33 |
34 | To make a parameter out of a variable:
35 |
36 | ```powershell
37 | param ($TerminatingCondition) # Any reasonable number of variables work here; just separate them with a comma each
38 | ```
39 |
40 | To convert a script into a function:
41 |
42 | ```powershell
43 | function New-MyFunction {
44 | # blah-blah, including the `param ()` block if you would like
45 | }
46 | ```
47 |
48 | To call the function:
49 |
50 | ```powershell
51 | # Run the script by dot-sourcing it, so the function is loaded onto the session
52 | . './path to/script.ps1'
53 |
54 | # Call the function with the parameters, just as you would a cmdlet
55 | New-MyFunction -TerminatingCondition 5
56 | ```
57 |
58 | To create a script block instead of a function
59 |
60 | ```powershell
61 | # Define the script block
62 | $MyScriptBlock = {
63 | # blah-blah
64 | }
65 |
66 | # Call the script block using the calling operator
67 | & $MyScriptBlock
68 | ```
69 |
70 | To measure the running duration of a certain command, script or a function:
71 |
72 | ```powershell
73 | Measure-Command New-MyFunction
74 | ```
75 |
76 | ## Important points to remember:
77 |
78 | 1. `*-Host` cmdlets send/receive content to/from the Information stream (and subsequently, the host). This stream does not interact with the pipeline.
79 | 2. Simply call the variable whose value you would like the function to return; there is no need to use the `return` keyword. However, make every function return only one kind of object because it affects how the output is used. Use `Get-Member` to see what object is output.
80 | 3. Name the functions like you would name cmdlets; use approved verbs.
--------------------------------------------------------------------------------
/cheatsheets/chapter-12.md:
--------------------------------------------------------------------------------
1 | # Advanced Concepts of Functions
2 |
3 | To set a parameter as positional and mandatory (0 stands for position 1):
4 |
5 | ```powershell
6 | param (
7 | [Parameter(Mandatory=$true, Position=0)]
8 | [datatype]
9 | $MyParameter
10 | )
11 | ```
12 |
13 | To assign a default value to a parameter:
14 |
15 | ```powershell
16 | param (
17 | [Parameter(Mandatory=$false)]
18 | [datatype]
19 | $MyParameter = 21
20 | )
21 | ```
22 |
23 | To set a parameter alias for a parameter:
24 |
25 | ```powershell
26 | param (
27 | [Parameter(Mandatory=$true, Position=0)]
28 | [Alias("mp")]
29 | [datatype]
30 | $MyParameter
31 | )
32 | ```
33 |
34 | To create a parameter set:
35 |
36 | ```powershell
37 | [CmdletBinding(DefaultParameterSetName='First')]
38 | param (
39 | # To make a parameter part of multiple parameter sets
40 | [Parameter(Mandatory=$true, Position=0, ParameterSetName='First')]
41 | [Parameter(Mandatory=$true, Position=0, ParameterSetName='Second')]
42 | [string]
43 | $ParamCommon,
44 |
45 | [Parameter(Mandatory=$true, Position=1, ParameterSetName='First')]
46 | [string]
47 | $ParamOne,
48 |
49 | [Parameter(Mandatory=$true, Position=1,
50 | ParameterSetName='Second')]
51 | [string]
52 | $ParamTwo
53 | )
54 | ```
55 |
56 | To add parameter validation:
57 |
58 | ```powershell
59 | param (
60 | [Parameter(Mandatory=$false, Position=0)]
61 | [ValidateSet(5, 10, 15, 20)]
62 | [int]
63 | $MyParameter
64 | )
65 | ```
66 |
67 | To add a simple dependency to a function, use the `begin` block:
68 |
69 | ```powershell
70 | function New-MyFunction {
71 | param (
72 | $MyParameter
73 | )
74 | begin {
75 | # Call the dependencies here
76 | }
77 | # Main function body
78 | }
79 | ```
80 |
81 | Alternatively, use a `process` and an `end`:
82 |
83 | ```powershell
84 | function New-MyFunction {
85 | param (
86 | $MyParameter
87 | )
88 | begin {
89 | # Dependencies
90 | }
91 | process {
92 | # Main function body
93 | }
94 | end {
95 | # Cleanup
96 | }
97 | }
98 | ```
99 |
100 | To break out of the function itself if a dependency fails:
101 |
102 | ```powershell
103 | begin {
104 | try {
105 | # Load dependency with -ErrorAction Stop
106 | }
107 | catch {
108 | break
109 | }
110 | }
111 | ```
112 |
113 | To add a confirmation prompt and `WhatIf` in a function:
114 |
115 | ```powershell
116 | function New-MyFunction {
117 | [CmdletBinding(ConfirmImpact = 'High', SupportsShouldProcess=$true)]
118 | param (
119 | # Your parameter block
120 | )
121 | process {
122 | if ($PsCmdlet.ShouldProcess("Item on which the operation is performed", "Action that would be performed")) {
123 | # Perform the action
124 | }
125 | }
126 | }
127 | ```
128 |
129 | To add help to functions, use the command-based help syntax.
130 |
131 | ```powershell
132 | function New-MyFunction {
133 | <#
134 | .SYNOPSIS
135 | # A short summary of what your function does.
136 |
137 | .DESCRIPTION
138 | Describe what the function does.
139 |
140 | .PARAMETER ParameterOne
141 | Helpful information about the parameter.
142 |
143 | .PARAMETER ParameterTwo
144 | Helpful information about the parameter.
145 |
146 | .EXAMPLE
147 | New-MyFunction -ParameterOne 'Value'
148 |
149 | .NOTES
150 | Any additional notes about the function (even attribution)
151 | #>
152 | }
153 | ```
154 |
155 | **Tip**: Start a comment block right above the function declaration to get the fields populated automatically.
156 |
157 | To add support for pipeline input:
158 |
159 | ```powershell
160 | function New-MyFunction {
161 | param (
162 | # The path to the file (or the name)
163 | [Parameter(ValueFromPipeline)]
164 | [string[]]
165 | $MyParameter
166 | )
167 | }
168 | ```
169 |
170 | The following kinds of pipeline input are allowed:
171 |
172 | - Accept input by type
173 | - With coercion
174 | - Without coercion
175 | - Accept input by parameter name
176 | - With coercion
177 | - Without coercion
178 |
179 | If your script contains several functions, which are already being called in a certain order from within each other, but you would like to improve readability, use the `Main` function:
180 |
181 | ```powershell
182 | function Main {
183 | New-MyFunctionThree
184 | }
185 |
186 | function New-MyFunction {
187 | # Some tasks
188 | }
189 |
190 | function New-MyFunctionTwo {
191 | New-MyFunction
192 | }
193 |
194 | function New-MyFunctionThree {
195 | New-MyFunctionTwo
196 | }
197 |
198 | Main
199 | ```
200 |
201 | If you are writing a script module, and would only like to expose a single function to the user:
202 |
203 | ```powershell
204 | function New-MyFunction {
205 | # Some tasks
206 | }
207 |
208 | function New-MyFunctionTwo {
209 | New-MyFunction
210 | }
211 |
212 | function New-MyFunctionThree {
213 | New-MyFunctionTwo
214 | }
215 |
216 | Export-ModuleMember New-MyFunctionThree
217 | ```
218 |
219 | To do something when a certain module is called using `Remove-Module` (such as cleanup), add the following to the end of the module file:
220 |
221 | ```powershell
222 | $MyInvocation.MyCommand.ScriptBlock.Module.OnRemove = {
223 | # Anything you would like done as part of module removal
224 | }
225 | ```
226 |
227 | If you would like to ensure that the aforementioned steps be taken even if the PowerShell session is closed, append the file with the content below:
228 |
229 | ```powershell
230 | Register-EngineEvent PowerShell.Exiting {
231 | # Your cleanup steps here
232 | }
233 | ```
--------------------------------------------------------------------------------
/cheatsheets/chapter-13.md:
--------------------------------------------------------------------------------
1 | # Debugging and Error Handling
2 |
3 | To enable debugging on a script, either:
4 |
5 | 1. Set the `DebugPreference` to `Continue`, or
6 | 2. Add (even an empty) `[CmdletBinding()]` line to the beginning of the function
7 |
8 | Run the function with the `-Debug` switch to get debug information displayed on the host.
9 |
10 | ```powershell
11 | New-MyFunction -MyParameter 'Value' -Debug
12 | ```
13 |
14 | If you would like to step through each line in the function as part of debugging:
15 |
16 | ```powershell
17 | # Set debugging on
18 | Set-PsDebug -Step
19 |
20 | # Call your function
21 | New-MyFunction -MyParameter 'Value'
22 |
23 | # Exit the debug mode using the -Off switch
24 | Set-PsDebug -Off
25 | ```
26 |
27 | To get into the trace mode for degugging, use the `-Trace` switch.
28 |
29 | ```powershell
30 | Set-PsDebug -Trace 1 # or 2
31 | ```
32 |
33 | To set a breakpoint:
34 |
35 | ```powershell
36 | Set-PsBreakpoint -Script ./path/to/script.ps1 -Line 5
37 | ```
38 |
39 | To list out all the breakpoints or remove the breakpoints:
40 |
41 | ```powershell
42 | # List breakpoints
43 | Get-PsBreakpoint
44 |
45 | # Remove breakpoints
46 | Remove-PsBreakpoint -Id 1 # as in the relevant ID as per Get-PsBreakpoint
47 | ```
48 |
49 | To set a conditional breakpoint (breakpoint that works if a certain condition is met):
50 |
51 | ```powershell
52 | # First, set the condition
53 | $Condition = { if ($Count -lt 2 <# Or any other relevant condition #>) { break } }
54 |
55 | # Now, set the breakpoint on the script
56 | Set-PsBreakpoint ./path/to/script.ps1 -Line 5 -Action $Condition
57 | ```
58 |
59 | To see if there was an error in the previous statement (within a script):
60 |
61 | ```powershell
62 | $?
63 | # Returns a Boolean output; TRUE means 'successfully executed'
64 | ```
65 |
66 | If a native command was run and the command exited in an error, the error is recorded in the automatic variable, `$LASTEXITCODE`.
67 |
68 | To hide errors at the terminal, (but continue to record them), use either:
69 |
70 | ```powershell
71 | # The common switch parameter
72 | New-MyFunction -ErrorAction SilentlyContinue
73 |
74 | # Or set the error action preference (use carefully; not recommended unless you know what you're doing)
75 | Set-Variable ErrorActionPreference 'SilentlyContinue'
76 |
77 | # Alternatively
78 | $ErrorActionPreference = 'SilentlyContinue'
79 | ```
80 |
81 | To list out all the errors encountered in the current session (unless the error variable was cleared)
82 |
83 | ```powershell
84 | $Error
85 | ```
86 |
87 | Treat this variable like a LIFO array, meaning, `$Error[0]` is the last error that was encountered. There are several properties in the variable.
88 |
89 | To clear the error variable, use the `Clear()` method baked into it:
90 |
91 | ```powershell
92 | $Error.Clear()
93 | ```
94 |
95 | To control flow based on errors, use the `try`-`catch`-`finally` construct:
96 |
97 | ```powershell
98 | try {
99 | # Some action here, with `-ErrorAction Stop` to make it terminating
100 | }
101 | catch [System.IO.DirectoryNotFoundException] <# Or any exception name as shown by the `Exception:` line of the error #> {
102 | # Actions to take in case of this exception
103 | }
104 | catch {
105 | # Catch-all statment: In case of any exception other than the above
106 | }
107 | finally {
108 | # The `finally` actions
109 | }
110 | ```
--------------------------------------------------------------------------------
/miscellaneous/Microsoft.VSCode_profile.ps1:
--------------------------------------------------------------------------------
1 | function prompt {
2 | $Location = (Get-Location).Path.ToString()
3 | switch -Wildcard ($Location) {
4 | "/home/$env:USERNAME" { $Location = '~'; break }
5 | "/home/$env:USERNAME/Documents" { $Location = 'Documents'; break }
6 | "/home/$env:USERNAME/Downloads" { $Location = 'Downloads'; break }
7 | "/home/$env:USERNAME/Pictures" { $Location = 'Pictures'; break }
8 | "/home/$env:USERNAME/Videos" { $Location = 'Videos'; break }
9 | "/home/$env:USERNAME/Music" { $Location = 'Music'; break }
10 | "/home/$env:USERNAME/Documents/code" { $Location = 'Code'; break }
11 | "/home/$env:USERNAME/*" { $Location = $Location.Replace("/home/$env:USERNAME/", '~/'); break }
12 | Default { }
13 | }
14 |
15 | Write-Host "PS " -NoNewline
16 | Write-Host `
17 | ($($env:USERNAME) + "@" + "$([System.Net.Dns]::GetHostByName((hostname)).HostName) ") `
18 | -NoNewLine -ForegroundColor Cyan
19 | Write-Host "$Location" -NoNewline -ForegroundColor Green
20 | Write-Host ("`n> ") -NoNewline
21 | return " "
22 | }
--------------------------------------------------------------------------------