B Miscellaneous

______________________________________________

In This Chapter

  • Introduction
  • Menus
  • Aliases
  • Foreach-Object (%)
  • PowerShell Interface Customization

______________________________________________

Introduction

Up to this point, we’ve covered numerous topics from how to start out scripting to customizing Exchange Online topics in PowerShell. The topics covered in this chapter, as with the rest of the book, are based on practical experience and are ones that should prove useful in a production environment.

For this chapter, we’ll cover menus, aliases, Foreach-Object filtering, and special permission cmdlets. Each of these provide some added benefit to managing the Security and Compliance Center with PowerShell. Aliases provide a way to customize PowerShell for easier coding. These shortcuts simply make coding easier. In addition to this, the shell can also be customized in terms of path, colors and window sizing.

Menus: How to create and add a menu of options in order to run functions in a script.

Alias: Creating new or using existing shortcuts for cmdlets in PowerShell.

Foreach-Object: Advanced filtering of results found from one-liners.

PowerShell Interface Customization: Going beyond the default and making adjustments for your own style.

Menus

Building menus is not a task that is necessary for one-off scripts. Menus should be used on scripts that will be run on multiple occasions, for example documenting settings in the Security and Compliance Center or for occasions where occasional input may be necessary. Another reason to use it is for a reusable script, which is especially useful for consultants who run their scripts in dozens of environments a year. The menu simply makes running the script quicker and more flexible.

In a PowerShell script, the menu can consist of two parts. The first part is the text for the menu which is the visual part of the script. The menu can be simple and singular in color or very colorful like the example given in Chapter 2. The second part is the infrastructure or back-end of the menu itself. This is where the executable code is stored and where coding needs to be performed in the form of functions that will complete the tasks the menu has called.

Sample Menu Code

$Menu = {

Write-Host "******************************************************************"

Write-Host "Compliance Cases"

Write-Host "******************************************************************"

Write-Host "1) Document existing cases"

Write-Host "2) Close cases"

Write-Host "3) Open a new case"

Write-Host "99) Exit"

Write-Host ""

Write-Host "Select an option.. [1-99]?"

}

The above menu has been snipped from a script that is used to manage Compliance Cases that are/were created in the Security and Compliance Center. We can open, close, document and manage rights using a menu and code that goes behind it. This is where PowerShell will make calls to functions in the rest of the script to perform the functions you code for.

To start this section, construct a ‘Do { } While’ code block. The reason for this is that script will keep running options and displaying the menu until an exit code is chosen. So the ‘Do { } While’ block would look something like this:

Do {

Invoke-Command -ScriptBlock $Menu

$Choice = Read-Host

} While ($Choice -ne 99)

Notice that with this code, the loop will keep displaying the menu after each option is chosen until the value of 99 is selected. At that point the script will stop and exit to a PowerShell prompt. The Read-Host will store the value type in $Choice to be used for selecting which code block to run. Next, there needs to be a way to decide which option will run. What PowerShell cmdlet will allow for this?

Switch ($Choice)

However, a review of the help on ‘Switch’ does not reveal a lot of clues for its usefulness/functionality. However with a little bit of help from your favorite search engine, one can find this MSDN link for PowerShell functionality:

https://technet.microsoft.com/en-us/library/hh847750.aspx

We find that Switch will act like a condition tester, if a condition is fed to it, it will select that option within the Switch code section. For example:

$Choice = 3

Switch ($Choice) {

1 {Write-Host “1”}

2 {Write-Host “2”}

3 {Write-Host “3”}

}

The result of this will display the number 3:

Let’s incorporate this into our menu infrastructure. Using the above as an example, we’ll need to build code blocks for each function and we'll need to call from our example on the previous page. To make this process simpler (in terms of the scope of the menu) functions are pre-created:

Document existing cases: Produces output with a list of cases and information on the cases

Close cases: Allows us to close existing cases

Open a new case: Code for opening new cases

Grant/Remove Rights: Change rights, add rights, remove rights, etc.

With these functions created they can be referred to in each option code block. Note that it is assumed that a connection to the Security and Compliance Center has already been made prior to running any of the options.

Option 1 - This option calls the function:

Function DocumentComplianceCases {

$Path = (Get-Item -Path "." -Verbose).FullName

$File = 'ComplianceCases.txt'

$Destination = $Path+''+$File

$ComplianceCasesNames = (Get-ComplianceCase).Name

Foreach ($ComplianceCasesName in $ComplianceCasesNames) {

Write-Host "Examining Compliance Case $ComplianceCasesName" -ForegroundColor Cyan

Write-Host "----------------------------------------------" -ForegroundColor Cyan

Get-ComplianceCase $ComplianceCasesName | Export-CSV -Notype $Destination

}

}

# Run function:

DocumentComplianceCases

Option 2

This option calls the function:

Function CloseCases {

Write-Host 'Specify the case you wish to close: ' -NoNewLine

$Name = Read-Host

$Case = $True

Try {

Get-ComplianceCase $Name -ErrorAction STOP

} Catch {

$Case = $False

Write-Host 'case not found'

}

If ($Case) {

Try {

Set-ComplianceCase $Name -Close -ErrorAction STOP

Write-Host "Able to close the $Name Compliance Case." -ForegroundColor Green

} Catch {

Write-Host "Unable to close the $Name Compliance Case." -ForegroundColor Yellow

}

}

} # End of Close Cases Function

CloseCases

Option 3

Function OpenCases {

Write-Host 'Specify a name of the new case you wish to create: ' -NoNewline

$Name = Read-Host

Write-Host 'Specify a description for the new case: ' -NoNewline

$Description = Read-Host

Try {

New-ComplianceCase $Name -Description $Description -ErrorAction STOP

} Catch {

Write-Host 'Failed to create a new Compliance Case' -ForegroundColor Red

}

} # End of Open Cases Function

OpenCases

Option 99

99 {# Exit

Write-Host "Exiting..."

}

When option 99 is selected, the script exits because of the Do {} While code block.

Pulling all of the previous code together into one script:

$Menu = {

Write-Host "******************************************************************"

Write-Host "Compliance Cases"

Write-Host "******************************************************************"

Write-Host "1) Document existing cases"

Write-Host "2) Close cases"

Write-Host "3) Open a new case"

Write-Host "99) Exit"

Write-Host ""

Write-Host "Select an option.. [1-99]?"

}

Do {

Invoke-Command $Menu

$Choice = Read-Host $Menu

Switch ($Choice) {

1 { # DocumentComplianceCases

DocumentComplianceCases

}

2 { # Close Compliance Cases

CloseCases

}

3 { # Open Compliance Cases

OpenCases

}

99 {# Exit

Write-Host "Exiting..."

}

Default {

Write-Host "You haven't selected any of the available options."

}

}

} While ($Choice -ne 99)

Running the script provides a menu as displayed below:

Option 99 allows for the script to exit:

If an option is typed in wrong, say 77, an error message is provided:

Aliases

PowerShell aliases are shortened versions of PowerShell cmdlets. Consider aliases to be a convenience in reducing the amount of text in a script. Aliases are not necessary for writing a script but they do provide shortcuts to coding. Without aliases, each command in PowerShell just takes longer to type. The downside of aliases is that normally PowerShell is a very readable scripting language and using aliases can obscure the ability to read PowerShell in plain English. Another downside is that there is no guarantee that the alias will exist in a different environment. If the script is meant to be portable, it is advisable to not use them or at least limit their usage. If a script will be read by someone other than you, using aliases might make the script unreadable to others.

Get-Alias -Definition Foreach-Object

However, what if you don't know the command that the alias is for? The above can be reverse engineered to show all aliases. To look up all aliases, simply type in 'Get-Alias':

Without listing them all here, there are 148 aliases defined. What may be more interesting is that aliases can be created and modified. This certainly provides for some flexibility or customization of PowerShell.

New-Alias

If there is a desire to make custom aliases for PowerShell, New-Alias is the cmdlet to use.

** Note ** The aliases are only good for the current session. If you close the current session, the alias is lost and when you reconnect to PowerShell the alias will not be there.

Get-Help New-Alias -Examples

Sample Usage

We can create an alias for just about anything in PowerShell that we want. For this example we can create aliases for any of the *-ComplianceCase cmdlets if we wanted to.

To create these aliases, we’ll use a series of New-Alias one-liners:

New-Alias gcc Get-ComplianceCase -Description 'Get Compliance Case'

New-Alias ncc New-ComplianceCase -Description 'New Compliance Case'

New-Alias scc Set-ComplianceCase -Description 'Set Compliance Case'

New-Alias rcc Remove-ComplianceCase -Description 'Remove Compliance Case'

Example result of a new alias creation:

There are a few parameters that can be used to customize this new alias during creation. One of the parameters is ‘Option’ which provides for a way to limit when the alias can be used – Global, Local, Script or Private. An alias could be enabled for only when a script runs or only while in a local session. The purpose of this option is to possibly isolate the usage of a cmdlet as to prevent unwarranted changes using the aliases. A description should be added so that the purpose of the alias is known by others.

Set-Alias

This cmdlet is used to modify any of the existing aliases to the specifics that you may want to configure for a particular alias. One of the exceptions is if the alias is set to ReadOnly. To modify one of those aliases, a ‘-Force’ switch must be used. Here are some sample uses of the cmdlet:

Get-Help New-Alias -Examples

Sample Usage

In practical terms, this cmdlet would likely only be used to modify existing aliases that you’ve created yourself. Taking some of the aliases created in the previous section, let’s make sure that the aliases are ReadOnly:

Set-Alias gcc Get-ComplianceCase -Option ReadOnly

Set-Alias ncc New-ComplianceCase -Option ReadOnly

Set-Alias rcc Remove-ComplianceCase -Option ReadOnly

Set-Alias scc Set-ComplianceCase -Option ReadOnly

What’s interesting is that this same cmdlet (‘Set-Alias’) can be used to create a new alias as well. For example, if a new alias were needed for creating a new mailbox on-premises. The Set-Alias could be used to create this alias as well:

Removing an Alias

Reviewing the PowerShell cmdlets with the word ‘Alias’ there are no cmdlets with the word ‘remove’ in them. How then can an alias be removed? If the solution cannot be found in PowerShell, then searching for a solution via your favorite search engine is the next step:

Search string: remove powershell alias

Reviewing the first link from the search, the solution to removing the alias is:

Remove-Item Alias:<alias to remove>

To remove one of the previous aliases that were created use this cmdlet:

Remove-Item Alias:ncc

However, there is an error:

That means the ‘ReadOnly’ setting that was applied worked as expected. To remove the ReadOnly option, run this:

Set-Alias ncc New-ComplianceCase –Force –Option None

Remove-Item Alias:ncc

Now if the alias is tried once more, PowerShell fails as the references have been removed:

In the end, creating your own aliases are not necessary when using PowerShell, but creating custom aliases may be a more efficient way to write code in PowerShell.

Foreach-Object (%)

While on the topic of PowerShell aliases, there are indeed some useful aliases that point to some rather useful cmdlets that we have not covered. One useful alias is ‘%’. What does the '%' symbol stand for or abbreviate in PowerShell? We can still use the Get-Alias cmdlet, but we need some criteria for finding just the '%' character in the results. If you recall from the Filtering section earlier in the book, the 'where' filter can help find the '%' symbol. From the screenshot, we also know that the field called 'Name' will contain the value:

Get-Alias | Where {$_.Name -eq "%"}

By using that cmdlet we now know that the alias % refers to Foreach-Object. Some other examples of other aliases:

Get-Alias | Where {$_.Name -eq "ft"}

Get-Alias | Where {$_.Name -eq "fl"}

Circling back to the '%' symbol or Foreach-Object. This particular alias provides for some interesting processing of data. Take for example a scenario where we need to get the SIP address for a user's account in Exchange Online. The address exists in the EmailAddresses property for a mailbox. It is one of a number of addresses that exist there. We can write a one-liner that can pull the entire EmailAddresses property and pull out just the SIP address. In the end, a report that shows this criteria needs to be created and the PowerShell one-liner looks like this:

Get-Mailbox | Select-Object DisplayName, @{Expression ={$_.EmailAddresses};Label='SIPAddress'} | % {$Mail = $_.SIPAddress ; $Email =$Null; Foreach ($Line in $Mail) {$Address = $Line -split ':'; $Prefix = $Address[0]; if ($Prefix -cmatch 'SIP') {$Email = $Address[1]}};if ($Email -eq $Null) {$Email = 'No SIP Address'};$_.SIPAddress = $Email;Return $_} | FT -Auto

Okay. Maybe that was a bit too much at once. Think of the above as what IT Management is looking for. To learn how the Foreach-Object or ‘%’ alias fit into this, start with the results of just the ‘Get-Mailbox’ that we need for the replication information.

Get-Mailbox

Notice that we get Name, Alias, ServerName and ProhibitSendQuota. This isn't what we need for our report. Yes, we can use Name and if we want an alias, but we really need to SIP address. We can start by using the Get-Mailbox cmdlet to reveal these mailbox properties in table format:

Get-Mailbox | where {$_.name -notlike 'Disc*'} | ft Name,Alias,EmailAddresses

** Note ** I also filtered out the Discovery Mailbox as this is not a user mailbox.

The table looks alright, however the EmailAddresses field is a mess. We also see the SIP address in the field, but we also see every other email address as well. We need to parse that field for that address. For readability sake we will also rename the field to 'SIPAddress'.

From the field data, we can determine that there are several address types stored in the EmailAddresses field - SMTP, smtp, SIP and SPO. SPO is for SharePoint Online, SMTP and smtp are our email addresses and SIP is used for Skype Online.

Let's start with the renaming of the column for the EmailAddresses property. This can be done instead of using 'Format-Table' we can use 'Select-Object' in conjunction with 'Expression' and 'Label' formatting method, like so:

Get-Mailbox | Where {$_.Name -NotLike 'Disc*'} | Select-Object DisplayName, @{Expression ={$_.EmailAddresses};Label='SIP Address'

This will then change the column heading to show as 'SIP Address' instead of 'Email Addresses':

Now that this is in place, we can now work with the data in the field and pull out just the SIP Address. How do we go about doing this? Well, we already have the data with which we will use the 'Select-Object' cmdlet. We can now manipulate this data with a Foreach-Object, or it's alias of '%'. With this we can manipulate the data using what amounts to a PowerShell code block. In this code block we need to pull out the SIP value from the series of values in the EmailAddresses field. One of the best ways is a Foreach loop to examine each one. We only store the one value that has the key letters 'SIP' in front of it. We can also register a 'No SIP value' phrase if we do not match these letters. First is the 'Foreach-Object' to kick it off:

| %

We store all of the Email Addresses in a new variable called $Mail. Notice the EmailAddresses value can be from the current object's EmailAddresses property by putting '$_.' in front of it. We can do this with any property if we wish to do so:

{$Mail = $_.EmailAddresses

Next we configure the $SIP variable as $Null. This variable will be used to store a SIP value if found or be left empty and used to trigger the phrase about no SIP address ($Null):

$SIP =$Null

The next code section is a Foreach loop that will process each entry stored in $Email in a loop:

Foreach ($Line in $Mail) {

Each entry in the field has a Prefix (SIP, SMTP, etc) that precedes the data we need. We can split that up the values in the $Line variable using a parameter called '-Split'. With this parameter we can then decide which character to separate out with. See these sample values we need to split:

We can store this separated value with the $Address like so:

$Address = $Line -split ':'

Now the $Address variable stores each part of the original field as a separate column and is numbered starting with the number '0':

$Prefix = $Address[0]

Once we store the Prefix value in the $Prefix variable we can check it to see if it contains our three special characters of 'SIP' and we also make sure that these letters are capitalized as well:

If ($Prefix -cmatch 'SIP') {

If there is a match, we can then process it by storing the address value ($Address - field 1) in a variable called SIP, like so:

$SIP= $Address[1]}}

Once this is done and all the addresses are processed, we can then check to see if the $SIP variable is empty. If it is empty, then the $SIP value is populated with 'No SIP Address' to indicate that no SIP address was found.

If ($SIP -eq $Null) {$SIP = 'No SIP Address'}

At the very end of the line, we need to then return this information back to be displayed, This requires we first use the original variable from the beginning ($EmailAddresses) as well as a 'Return' cmdlet:

$_.EmailAddresses = $SIP

Return $_}

Once all of these pieces are in place we now have a one-liner that will give us a mailbox's DisplayName and SIP address in a nicely formatted and labeled table:

Get-Mailbox | Select-Object DisplayName, @{Expression ={$_.EmailAddresses};Label='SIP Address'} | % {$Mail = $_.EmailAddresses ; $SIP =$Null; Foreach ($Line in $Mail) {$Address = $Line -split ':'; $Prefix = $Address[0]; If ($Prefix -cmatch 'SIP') {$SIP = $Address[1]}};If ($SIP -eq $Null) {$SIP = 'No SIP Address'};$_.EmailAddresses = $SIP ; Return $_} | FT -Auto

However, when we run this code, we get LOTS of red. What went wrong?

Well, the error message doesn't make sense, does it? The error states that the property 'EmailAddress'cannot be found on the object. It appears that the error message is related to the Mailbox object and its EmailAddresses object. However, this is not the case. The error relates to the label of the column, which is 'SIP Address' and the variable used in the Foreach-Object which is '$EmailAddresses'. These values are different, which causes the error message to occur. Instead, these values need to match like so:

Code Summary

Taking all of the above information and synthesizing it, we get this long one-liner to handle the heavy lifting for us. What is nice is that we can substitute the 'SIP' phrase for 'SMTP' or even 'smtp' if we want to customize it for a different search.

Get-Mailbox | Select-Object DisplayName, @{Expression ={$_.EmailAddresses};Label='SIPAddress'} | % {$Mail = $_.SIPAddress ; $Email =$Null; Foreach ($Line in $Mail) {$Address = $Line -split ':'; $Prefix = $Address[0]; If ($Prefix -cmatch 'SIP') {$Email = $Address[1]}};If ($Email -eq $Null) {$Email = 'No SIP Address'};$_.SIPAddress = $Email;Return $_} | FT -Auto

PowerShell Interface Customization

Working space is important in PowerShell and this means screen buffering. Why is this important? The default line buffer limit is 300 which can be too small depending on what script output of cmdlet output is being run. For example, just running 'Get-Help New-RetentionCompliancePolicy' can overrun that buffer. This makes it hard to use PowerShell to its fullest. So, just changing the buffer size will make PowerShell that much easier to work with.

** Note ** These changes are local to the machine where the changes are made.

Before - 300 Character Buffer:

To make the change, click on the icon in the upper left and select Properties (see below):

Adjust the 300 to 9999:

After - 9999 Character Buffer:

Notice the smaller size of the slider on the right. Now output from most, if not all cmdlets, will not exceed the window buffer size. If the output is in excess of 9999 lines, it may be better to export the results to a TXT, CSV or some other sort of file. Make sure to save these settings so we won't have to keep making this change.

In addition to the above, startup options can be created for the PowerShell window to customize it more. There are several locations for customization files for PowerShell and they vary in their functionality. The two we will work with for this chapter are:

For all users - PowerShell

%windir%system32Windows¬PowerShellv1.0Microsoft.Powershell_profile.ps1

Current user - PowerShell

%UserProfile%DocumentsWindowsPowerShellMicrosoft.Powershell_profile.ps1

Before creating a new one, verify that one has not yet been created. Backup the old profile if needed for later. First verify the current PowerShell profile:

$Profile

To see if the file was already created and in use (if $True, then the file exists, otherwise it does not):

Test-Path $Profile

In the above case, the profile has not been created and if we wish to add customizations we’ll need to create our own file.

New-Item -Path $Profile –ItemType File –Force

Once the file has been created you can open this in your favorite editor.

What Can Be Added to This File

The following is a list of some of the customizations that can be performed with the profile file:

  • Window sizing (height and width)
  • Load custom scripts
  • Windows colors

Window Sizing and Coloring

The size of the console is stored in this variable $Host which is a known variable in PowerShell.

$Host

Notice the UI parameter is for the User Interface. To find out what is stored in it, run this:

$Host.UI

That was rather unhelpful, how do we see the values stored for the UI so that changes can be made?

$Host.UI.RawUI

We now see the buffer size and Window Size as well as colors for the window. For this sample, the window will have a background of gray and a foreground of black. The buffer will be widened to 160 and lengthened to 6000. Next the Window Size will increase to 160 and then length to 85.

$Shell = $Host.UI.RawUI

$Shell.ForegroundColor = "Black"

$Shell.BackgroundColor = "Gray"

$Buffer = $Shell.BufferSize

$Buffer.Width = 160

$Buffer.Height = 6000

$Shell.BufferSize = $Buffer

$Window=$Shell.WindowSize

$Window.Width = 160

$Window.Height = 50

$Shell.WindowSize = $Window

The custom colors change the PowerShell window like this:

In the end, when the new customized PowerShell window is opened, there may be an error message displayed. The reason is that in order to load a script with the PowerShell window, the permissions for Script Execution need to be something above Restricted, which is the default permission. For example, the ‘RemoteSigned’ permission will allow the script to be loaded.

Set-ExecutionPolicy RemoteSigned

That will ensure the customizations will work. Loading scripts when opening a PowerShell window requires a couple of items. First changing the location of the PowerShell window to a directory where the scripts are stored:

Set-Location C:Psscripts

As a final step of configuring the profile script, we could run another script (below) stored in the above folder:

.CheckMailboxConfig.PS1

The example script above, would return various settings for our mailboxes - retention policies, quotas, OWA Mailbox Policy Mobile Device policies and more. Combining all of these steps together would result in this profile script:

# Load all shell parameters

$Shell = $host.UI.RawUI

$Shell.ForegroundColor = "Black"

$Shell.BackgroundColor = "Gray"

$Buffer = $Shell.BufferSize

$Buffer.Width = 160

$Buffer.Height = 6000

$Shell.BufferSize = $buffer

$Window=$Shell.WindowSize

$Window.Width = 160

$Window.Height = 50

$Shell.WindowSize = $Window

# Run Exchange Services check script

Set-Location C:Psscripts

.ExchangeServices.PS1

There are plenty of other options and additions that can be made to your PowerShell profile, but we will not cover all of those here.

..................Content has been hidden....................

You can't read the all page of ebook, please click here login for view all page.
Reset
18.226.28.197