Skip to content

Commit

Permalink
♻️ Refactor AboutCmdletVerbs (#378)
Browse files Browse the repository at this point in the history
* ♻️ Refactor AboutCmdletVerbs

* 🚀 Adjust build name

* ♻️ Address review comments

* ♻️ Address review comments
  • Loading branch information
vexx32 committed Mar 21, 2020
1 parent 6cc30eb commit b16400c
Show file tree
Hide file tree
Showing 2 changed files with 189 additions and 83 deletions.
266 changes: 186 additions & 80 deletions PSKoans/Koans/Introduction/AboutCmdletVerbs.Koans.ps1
Original file line number Diff line number Diff line change
Expand Up @@ -4,39 +4,53 @@ param()
<#
Cmdlet Verbs
The fundamental building block of PowerShell are cmdlets and functions.
The fundamental building block of PowerShell are cmdlets and functions, both
of which are named according to a Verb-Noun syntax by convention.
We'll cover functions later, but cmdlets are made up of the following syntax:
You can see the list of PowerShell's recommended / approved verbs by calling
Get-Verb in your PowerShell console, or going to the following docs page:
https://docs.microsoft.com/powershell/scripting/developer/cmdlet/approved-verbs-for-windows-powershell-commands
Verb-Noun
Each command should use a verb appropriate to the action it's taking, and a
noun that succinctly and clearly describes what it's acting upon.
With the verb being an action, and the noun representing the target of the command.
In this topic, we'll cover the 5 basic verbs which'll see you through the majority of your
PowerShell needs. But PowerShell has more than just 5 predefined verbs! You can see them
all by running the following cmdlet:
Get-Verb
In this topic, we'll cover a few of the most common verbs which you'll see
most frequently.
#>

Describe "Basic Verbs" {

BeforeAll {
# We'll be using this path later on.
$FilePath = "$env:TMP/YOUR_PATH.txt"

if (Test-Path $FilePath) {
Remove-Item -Path $FilePath
}
}

Context "Get" {
<#
Cmdlets with the Get verb are used for retrieving data.
So for example "Get-Process" will retrieve all the processes running on
your current machine.
So for example "Get-Process" will retrieve all the processes running
on your current machine.
#>

It 'is for commands that retrieve data' {
<#
Using the Get-Command cmdlet, which retrieves all available commands,
find 5 commands with the Get verb.
Using the Get-Command cmdlet, which retrieves all available
commands, find 5 commands with the Get verb.
Replace each ____ with the name of a Get-* command.
Fill in each blank with the name of a different Get-* command.
#>
$Answers = "____", "____", "____", "____", "____"
$Answers = @(
"____"
"____"
"____"
"____"
"____"
)
$Answers | Should -BeIn (Get-Command -Verb Get).Name

$Answers | Get-Unique | Should -HaveCount 5 -Because "five unique cmdlets are required"
Expand All @@ -47,15 +61,8 @@ Describe "Basic Verbs" {
<#
Cmdlets with the New verb are used to create data.
So for example 'New-GUID' will create a new GUID, or 'New-LocalUser' will create a local
user on your machine.
Before continuing with this exercise, try using the following code to create a file:
$Path = "YOUR PATH.txt"
New-Item -Path $Path -ItemType file
This will create a new text file, in the location you specify.
So for example 'New-Guid' will create a new GUID, or 'New-TimeSpan'
will create a new [timespan] object with the specified parameters.
#>

It 'is for commands that create data' {
Expand All @@ -64,34 +71,60 @@ Describe "Basic Verbs" {
Replace each ____ with the name of a New-* command.
#>
$Answers = "____", "____", "____", "____", "____"
$Answers = @(
"____"
"____"
"____"
"____"
"____"
)
$Answers | Should -BeIn (Get-Command -Verb New).Name

$Answers | Get-Unique | Should -HaveCount 5 -Because "five unique cmdlets are required"
}
}

Context "Add" {
<#
Cmdlets with the Add verb append data to an existing object or data source.
It 'can create a New-Item' {
<#
Let's try creating a file!
Use New-Item to create a new text file, in the location
specified with the $FilePath variable, which is defined above.
If you followed the example in the 'new' test, you can use Add-Content to add some
text to your newly created text file:
The necessary parameters are already filled in for you here. In
this case, the file we're creating is simply empty. You could
also specify a -Value parameter with some text to put in the
newly-created file.
$Path = "YOUR PATH.txt"
Add-Content -Path $Path -Value "Sgt. Bash is the best house robot because... fire."
Take some time to experiment with New-Item in your console if
you'd like to see what it can do! Start with:
Before continuing, run this command several times. See what happens; is it the
result you expected?
Get-Command New-Item -Syntax
Get-Help New-Item -Examples
#>

$File = ____ -Path $FilePath -ItemType File

# All "file" objects are of this type.
$File | Should -BeOfType [System.IO.FileInfo]

# An empty file has a "length" of zero.
$File.Length | Should -Be 0
}
}

You'll see that several lines of text were added to the file. This cmdlet only appends
information, it does not overwrite.
Context "Add" {
<#
Cmdlets with the Add verb append data to an existing object or data
source.
Basically, if it doesn't exist then a cmdlet with the add verb can probably be used
to make it so.
Essentially, if the target doesn't exist then a cmdlet with the Add
verb will typically create it. If it does exist, the cmdlet will
add data to it, if data can be added without overwriting the
original data.
A common example one might see working with Office 365 is calendar permissions.
If you want to grant permissions to somebody who doesn't have any, you use "Add-MailboxFolderPermission".
A common example one might see working with Office 365 is calendar
permissions. If you want to grant permissions to somebody who
doesn't have any, you use "Add-MailboxFolderPermission".
#>

It 'is for commands that append data' {
Expand All @@ -105,33 +138,62 @@ Describe "Basic Verbs" {

$Answers | Get-Unique | Should -HaveCount 5 -Because "five unique cmdlets are required"
}
}

Context "Set" {
<#
Cmdlets with the Set verb will overwrite information that already exists.
It 'can Add-Content to a file' {
<#
Try adding this content to the file we created above using
Add-Content.
#>
"Mountains are merely mountains." | ____ -Path $FilePath

<#
Let's see what happens if we add a whole bunch of things! Fill
in these blanks with whatever you like.
#>

If you followed the example in the 'New' and 'Add' tests, you can use set to do
something to your text file:
'____' | Add-Content -Path $FilePath
'____' | Add-Content -Path $FilePath
'____' | Add-Content -Path $FilePath
'____' | Add-Content -Path $FilePath

$Path = "YOUR PATH.txt"
Set-Content -Path $Path -Value "Sir Kill-A-Lot is the best house robot because of reasons."
# Let's check the contents of the file.
$FileData = Get-Content -Path $FilePath

Before continuing, run this command several times. See what happens, is it the
result you expected?
# How many lines did we end up with?
__ | Should -Be $FileData.Count

You'll see that there's only one line of text in the file. This is because the Set-Content command
will overwrite information that's already there.
<#
We can see that several lines of content were added to the file.
Add-* cmdlets can only append data, they can't overwrite. With
this information, you should be able to determine what the
expected content of the file is at this point.
#>

$ExpectedContent = @(
'Mountains are merely mountains.'
'____'
'____'
'____'
'The road onwards, the road back; which is the shorter?'
)

$ExpectedContent | Should -BeExactly $FileData
}
}

Some Set-* cmdlets require the instance to already be present for you to change it;
you'll need to use a New-* cmdlet first to create an instance before you can
overwrite information within it.
Context "Set" {
<#
Cmdlets with the Set verb will overwrite information that already
exists.
A common example one may see working with Office 365 is with calendar permissions.
If a user already has some permissions configured, you can use you use "Set-MailboxFolderPermission"
to change the user's permissions. However, attempting to use an Add cmdlet will fail;
Set-* commands overwrite data, but often can only do so if it already exists.
Some Set-* cmdlets require the instance to already be present for
you to change it; you'll need to use a New-* cmdlet first to create
an instance before you can overwrite information within it.
A common example one may see working with Office 365 is with
calendar permissions. If a user already has some permissions
configured, you can use "Set-MailboxFolderPermission" to change the
user's permissions.
#>

It 'is for commands that overwrite data' {
Expand All @@ -145,39 +207,83 @@ Describe "Basic Verbs" {

$Answers | Get-Unique | Should -HaveCount 5 -Because "five unique cmdlets are required"
}
}

Context "Remove" {
<#
Cmdlets with the Remove verb will delete data from an object or data source.
It 'can Set-Content for a file' {
<#
Let's try using Set-Content on our text file from before. But
first, let's check that it still has the contents we added. We
should still have 5 lines in it from before.
If you followed the example in the 'New','Add' and 'Set' tests, you can use Remove-Item to
delete your text file:
If you added extra lines to the file in the Add-Content koan
above, make sure to update the expected line count here!
#>
$LineCount = 5
Get-Content -Path $FilePath | Should -HaveCount $LineCount

# Now let's try setting the contents.
"Wherever you are, it's the place you need to be." | Set-Content -Path $FilePath

$Path = "YOUR PATH.txt"
Remove-Item -Path $Path
# So what should be in the file now?
$FileContent = Get-Content -Path $FilePath
"____" | Should -BeExactly $FileContent

Before continuing, run this command a few times. What happens when you try to run it
once the instance has been deleted?
# What happens if we set the contents again?
'____' | Set-Content -Path $FilePath
Get-Content -Path $FilePath | Should -BeExactly "Rest and be kind, you don't have to prove anything."
<#
You'll see that there's only one line of text in the file. This
is because the Set-Content command will completely overwrite
whatever is in the file already.
#>
}
}

You'll see that it fails. Cmdlets with the verb Remove simply remove data;
if the instance you're referring to doesn't exist, then there's nothing available
to remove and it will emit an error message.
Context "Remove" {
<#
Cmdlets with the Remove verb will delete data from an object or data
source.
Returning to Calendar permissions in Office 365, you can use a Remove cmdlet
to completely remove a user's permissions to a calendar.
#>
Once again with calendar permissions in Office 365, you can use a
Remove cmdlet to completely remove a user's permissions to a
calendar.
#>

It "is for commands that delete data" {
<#
Using Get-Command, find 5 commands with the Remove verb.
Using Get-Command, find 5 commands with the Remove verb.
Replace each ____ with the name of a Remove-* command.
#>
Replace each ____ with the name of a Remove-* command.
#>
$Answers = "____", "____", "____", "____", "____"
$Answers | Should -BeIn (Get-Command -Verb Remove).Name

$Answers | Get-Unique | Should -HaveCount 5 -Because "five unique cmdlets are required"
}

It 'can Remove-Item to delete a file' {
<#
We can use Remove-Item to delete the text file we've been
working with. Before we do, let's just double check the file
still exists. 'Leaf' here refers to a file; 'Container'
would be the corresponding type for a folder.
#>
Test-Path $FilePath -PathType Leaf | Should -BeTrue

# Pester has its own way of checking that files exist.
$FilePath | Should -Exist

# Use Remove-item to delete the file completely.
____ -Path $FilePath

# Let's check it was removed properly. Test-Path $FilePath -PathType Leaf | Should -BeTrue
Test-Path $FilePath | Should -BeFalse

<#
If we try to remove a file that doesn't exist, we should get
an error. What does that error look like?
#>
$Message = "____"
{ Remove-Item -Path $FilePath -ErrorAction Stop } | Should -Throw -ExpectedMessage $Message
}
}
}
6 changes: 3 additions & 3 deletions azure-pipelines.yml
Original file line number Diff line number Diff line change
Expand Up @@ -15,11 +15,11 @@ pr:
variables:
NupkgArtifactName: 'PSKoans.nupkg'
${{ if ne(variables['Build.Reason'], 'PullRequest') }}:
BuildName: '$(Date:yyyy-MM-dd) (#$(BuildID)) $(TeamProject) ($(SourceBranchName))'
Trigger: '$(SourceBranchName)'
${{ if eq(variables['Build.Reason'], 'PullRequest') }}:
BuildName: '$(Date:yyyy-MM-dd) (#$(BuildID)) $(TeamProject) (PR #$(System.PullRequest.PullRequestId))'
Trigger: 'PR #$(System.PullRequest.PullRequestNumber)'

name: '${{ variables.BuildName }}'
name: '$(BuildID)-$(Date:yyyy-MM-dd)$(Rev:.r) $(TeamProject) (${{ variables.Trigger }})'

stages:
- stage: UploadChangelog
Expand Down

0 comments on commit b16400c

Please sign in to comment.