Office 365 MFA – App Passwords

Continuing on from my previous blog post on Office 365 MFA, another common requirement is for App passwords.

App passwords are needed when Multi-factor Authentication is Enforced on your account to login with non-web based applications like Outlook and Skype for Buisness. These are single use, per application passwords that are separate from your normal password.

App passwords need to be automatically generated on the https://myapps.microsoft.com website for use in these applications, please note that these passwords can not be customized.

  1. You will first need to login to  https://myapps.microsoft.com using your Office 365 account. From here click your name the top right corner of the screen and select the Profile option.

  2. On the Profile page click “Additional security verification”
  3. On the Additonal Security Verification page click “app passwords” and then click create.
  4. Give your password a name to identify which application you plan to use the password with.
  5. Copy the password and paste it into the application when requested. Please note that you can not view this password again. If you need to reinstall the application later, the best option is to remove the old app password and create another. Don’t store these passwords.

Office 365 MFA – Push notifications using the mobile app

Multi-factor Authentication (MFA) is one of the essential 8 strategies to help mitigate cyber security incidents as recommended by the Australian Department of Defence. However the biggest complaints end users give after enabling MFA in Office 365 is the delay in receiving SMS messages and having to type in a 6 digit code.

Luckily there is a simple solution offered by Microsoft in the form of the Microsoft Authenticator App which is available for Windows PhoneAndroid, and iOS.

  1. You will first need to login to  https://myapps.microsoft.com using your Office 365 account. From here click your name the top right corner of the screen and select the Profile option.

  2. On the Profile page click “Additional security verification”
  3. Check the box next to Authenticator App and then click the configure button
  4. Install the App onto your mobile device from the relevant store:  Windows PhoneAndroidiOS.
  5. Tap the app menu and select Add Account, then choose Work or School Account, and then scan the Barcode on your computer screen with your device’s camera.
  6. Back on the computer click Done, then on the “Additional Security Verification” page click Save.
  7. Go back into “Additional Security Verification” page from Step 2
  8. Change your preferred option to “Notify me though app” and click save.
  9. You will then need to verify the new method on your phone when the push notification appears.

You can now use notification on your phone to verify your account on Office 365.

 

Office 365 products you might not know about

The more I talk to people about how they are using their Office 365 subscription, the more I notice how people are missing out on quite a lot of value that is included as part of the service, sometimes this includes the obvious ones like Skype for Business and SharePoint but there are many others that people just don’t seem to know about. Here is a few of the ones I find most people know nothing about.

Microsoft Bookings

https://products.office.com/en-us/business/scheduling-and-booking-app
This is a great service for people on a Business Premium subscription (there is a way to enable this for E3 and E5 clients also) where you can activate a pubic bookings page for your clients. It hooks into your calendars to provide available booking times and also comes with a handy app where you can accept of decline bookings.

Additionally it allows you to group people with services and it also lets you set some pricing information.

To enable this for E3 and E5 customers first enable first release for all users in your admin center and then go to this link: https://outlook.office.com/owa/?path=/bookings

Microsoft Staff Hub

https://staffhub.ms/
Staff hub is a time management system for businesses who have shift workers and deskless staff. Once again it has its own mobile app and allows managers to assign shifts while allowing staff to swap them. Additionally it has some lite document management and collaboration features. It is available on the K1, E1, E2, E3, and E5 plans.

Microsoft Flow

https://flow.microsoft.com/
Microsoft flow is used for automating business processes, it can do everything from sending you a phone notification when someone updates a file, to saving attachments automatically to cloud storage and much, much more.

The best feature of Microsoft Flow is it has a free plan and you don’t even need Office 365, in fact you can use it for automating processes that have nothing to do with Office 365 at all. For example you could send twitter post to a Google sheet or post a twitter update each time you add a photo to instagram.

Thanks for reading.

PowerShell 5 classes (As of Win10 Tech Preview 9926)

It has taken me a little while to work out the new class feature in PowerShell 5 preview. Each preview so far has seemed to slightly change the way classes work, so if you are using a later preview or the actual release some syntax might change slightly between now and then.

So what are classes and why would you want them? The easiest way I can think to describe them is that the objects you have been using so far in PowerShell are cookies, and classes are the cookie cutters. They are a structured way to define an object type that you can the use to define your objects in a more structured way.

Take the System.ServiceProcess.ServiceController object type for example, this is the object type you get when you run Get-Service. If you run Get-Service and pipe it to Get-Member you get a range of properties and methods, if you create your own custom object by using a hash table you will get a range of properties but there is no easy way to add your own methods. Also the ServiceController object is always the same, no matter what service you are looking at. They all have the same properties and methods, this is because they all came from the same class.

In the following example I will make a class that you could use to define objects that can later be used to build a html report.

So how do you define a class? firstly you do a very similar thing to how you would already create functions, give it a name:

Class ReportTable
{
}

Next you need to define what properties the object will have, in this example I want a Title to refer to the object as and use as a header in the report, a Description for my report, an Object like a service object I can add to the report as a table of data, an Order so I can control where in the report each object goes and an EntryType so that I can make any errors or warnings stand out more, and finally an As property so that we can structure the object as a table or a list.

You will notice that you can still cast each property’s type, for example Int or String, and you can provide other parameter properties like validatesets the same way you can do in functions.

Class ReportTable
{
 [String]$Title
 [String]$Description
 [ValidateSet("Error","Warning","Information")][String]$EntryType
 $Object
 [ValidateRange(0,100)][Int]$Order
 [ValidateSet("Table","List")][String]$As
}

You can now create objects based on this class by casting a new variable to the class name you specified, note that you need to run this in a single run instance which I will explain later in this article.

$newVar = [ReportTable]::new()

You can then manipulate the data in the object by referring to its properties, for example:

$newVar.Title = 'Hello World'

You will notice that whenever you create an instance of this class as a new object it will have no data, if you want to be able to add data on creation you will need to define a constructor. In this example I have created a constructor that accepts values for all properties. You need to use the syntax $This.property to refer to properties of the class.

Class ReportTable
{
   [String]$Title
   [String]$Description
   [ValidateSet("Error","Warning","Information")][String]$EntryType
   $Object
   [ValidateRange(0,100)][Int]$Order
   [ValidateSet("Table","List")][String]$As

   ReportTable([string]$newTitle, [String]$newDescription,[String]$newEntryType,$newObject,[Int]$newOrder,[String]$newAs)
   {
      $this.Title = $newTitle;
      $this.Description = $newDescription;
      $this.EntryType = $newEntryType;
      $this.Object = $newObject;
      $this.Order = $newOrder;
      $this.As = $newAs;
   }
}

To create an object based on this new constructor you can do the following

$obj = Get-Service *bits* | select DiplayName, Status
$newVar = [ReportTable]::new('Bits Service','This is the current status of the Background Intelligent Transfer Service','Information',$obj,'1','Table')

But sometimes you might not want to specify that it will be in a table, but use table as a default. In this case you can create multiple constructors like follows:

Class ReportTable
{
   [String]$Title
   [String]$Description
   [ValidateSet("Error","Warning","Information")][String]$EntryType
   $Object
   [ValidateRange(0,100)][Int]$Order
   [ValidateSet("Table","List")][String]$As

   ReportTable([string]$newTitle, [String]$newDescription,[String]$newEntryType,$newObject,[Int]$newOrder,[String]$newAs)
   {
      $this.Title = $newTitle;
      $this.Description = $newDescription;
      $this.EntryType = $newEntryType;
      $this.Object = $newObject;
      $this.Order = $newOrder;
      $this.As = $newAs;
   }
   ReportTable([string]$_title, [String]$_description,[String]$_entryType,[Psobject]$_object,[Int]$_order)
   {
      $this.Title = $_title;
      $this.Description = $_description;
      $this.EntryType = $_entryType; 
      $this.Object = $_object;
      $this.Order = $_order;
      $this.As = "Table";
   }
}

You will notice that in the second constructor it does not expect a table to be specified and that it has table hard coded. Note that if you specify a constructor you will no longer be able to create a empty version of the object. If you still want to be able to do this you need to specify an empty constructor like follows:

Class ReportTable
{
   [String]$Title
   [String]$Description
   [ValidateSet("Error","Warning","Information")][String]$EntryType
   $Object
   [ValidateRange(0,100)][Int]$Order
   [ValidateSet("Table","List")][String]$As

   ReportTable([string]$newTitle, [String]$newDescription,[String]$newEntryType,$newObject,[Int]$newOrder,[String]$newAs)
   {
      $this.Title = $newTitle;
      $this.Description = $newDescription;
      $this.EntryType = $newEntryType;
      $this.Object = $newObject;
      $this.Order = $newOrder;
      $this.As = $newAs;
   }
   ReportTable([string]$_title, [String]$_description,[String]$_entryType,[Psobject]$_object,[Int]$_order)
   {
      $this.Title = $_title;
      $this.Description = $_description;
      $this.EntryType = $_entryType; 
      $this.Object = $_object;
      $this.Order = $_order;
      $this.As = "Table";
   }
   ReportTable(){}
}

Now that we have a class with some properties attached we can add methods. Methods are useful because they can be used to manipulate the object you created at any stage further along in your code. In this example I will make a method that will convert the $object stored in our class into html. We do this by using the void keyword.

Class ReportTable
{
   [String]$Title
   [String]$Description
   [ValidateSet("Error","Warning","Information")][String]$EntryType
   $Object
   [ValidateRange(0,100)][Int]$Order
   [ValidateSet("Table","List")][String]$As

   ReportTable([string]$newTitle, [String]$newDescription,[String]$newEntryType,$newObject,[Int]$newOrder,[String]$newAs)
   {
      $this.Title = $newTitle;
      $this.Description = $newDescription;
      $this.EntryType = $newEntryType;
      $this.Object = $newObject;
      $this.Order = $newOrder;
      $this.As = $newAs;
   }
   ReportTable([string]$_title, [String]$_description,[String]$_entryType,[Psobject]$_object,[Int]$_order)
   {
      $this.Title = $_title;
      $this.Description = $_description;
      $this.EntryType = $_entryType; 
      $this.Object = $_object;
      $this.Order = $_order;
      $this.As = "Table";
   }
   ReportTable(){}

   [void]ToHtml()
   {
      $this.Object = ConvertTo-Html -InputObject $this.Object -Fragment
   }
}

We can call this method using the dot notation as follows:

$obj = Get-Service *bits* | select DiplayName, Status
$newVar = [ReportTable]::new('Bits Service','This is the current status of the Background Intelligent Transfer Service','Information',$obj,'1','Table')
$newVar.ToHtml()

Now there is a string stored on the $object property which contains a html version of the original service object.

We can also pass data into methods like in the following example, here we will be able to add or subtract a specified value from the order property.

Class ReportTable
{
   [String]$Title
   [String]$Description
   [ValidateSet("Error","Warning","Information")][String]$EntryType
   $Object
   [ValidateRange(0,100)][Int]$Order
   [ValidateSet("Table","List")][String]$As

   ReportTable([string]$newTitle, [String]$newDescription,[String]$newEntryType,$newObject,[Int]$newOrder,[String]$newAs)
   {
      $this.Title = $newTitle;
      $this.Description = $newDescription;
      $this.EntryType = $newEntryType;
      $this.Object = $newObject;
      $this.Order = $newOrder;
      $this.As = $newAs;
   }
   ReportTable([string]$_title, [String]$_description,[String]$_entryType,[Psobject]$_object,[Int]$_order)
   {
      $this.Title = $_title;
      $this.Description = $_description;
      $this.EntryType = $_entryType; 
      $this.Object = $_object;
      $this.Order = $_order;
      $this.As = "Table";
   }
   ReportTable(){}

   [void]ToHtml()
   {
      $this.Object = ConvertTo-Html -InputObject $this.Object -Fragment
   }
   [void]AddOrder([int]$_add)
   {
      $this.Order += $_add;
   }
   [void]SubtractOrder([int]$_subtract)
   {
      $this.Order -= $_subtract;
   }
}

Now if we specify a integer in the AddOrder method the order property will increment by the specified value.

It is worth noting that the validaterange will still apply to the order value even after the object is created. So if you try to add 100 to the order value when it was previously 1 then that would total 101, which is outside the range of (0, 100) and you will get the validation error displayed.

You can also overload the methods like we did with constructors, in this example I will add 2 more methods to add or subtract ‘1’ from the order if you call $newVar.AddOrder() and don’t specify a value.

Class ReportTable
{
   [String]$Title
   [String]$Description
   [ValidateSet("Error","Warning","Information")][String]$EntryType
   $Object
   [ValidateRange(0,100)][Int]$Order
   [ValidateSet("Table","List")][String]$As

   ReportTable([string]$newTitle, [String]$newDescription,[String]$newEntryType,$newObject,[Int]$newOrder,[String]$newAs)
   {
      $this.Title = $newTitle;
      $this.Description = $newDescription;
      $this.EntryType = $newEntryType;
      $this.Object = $newObject;
      $this.Order = $newOrder;
      $this.As = $newAs;
   }
   ReportTable([string]$_title, [String]$_description,[String]$_entryType,[Psobject]$_object,[Int]$_order)
   {
      $this.Title = $_title;
      $this.Description = $_description;
      $this.EntryType = $_entryType; 
      $this.Object = $_object;
      $this.Order = $_order;
      $this.As = "Table";
   }
   ReportTable(){}

   [void]ToHtml()
   {
      $this.Object = ConvertTo-Html -InputObject $this.Object -Fragment
   }
   [void]AddOrder([int]$_add)
   {
      $this.Order += $_add;
   }
   [void]SubtractOrder([int]$_subtract)
   {
      $this.Order -= $_subtract;
   }
   [void]AddOrder()
   {
      $this.Order += 1;
   }
   [void]SubtractOrder()
   {
      $this.Order -= 1;
   }
}

Earlier I mentioned that you needed to refer to the class in the same run instance for it to work. Let me try to explain this further: If you define a class in ISE and then press F5 and then try to create an object using this class in the interactive shell pane it will throw an error saying the class does not exist.

This is because the class definition only lasts as long as the currently running script. In the above case you would need to define the class in the script pane and then also refer to it in the last few lines of the script pane and run the whole script at once.

After you create the object you can change all the properties and call the methods from the class but you can not create any new objects from that class.

Think of it this way, a class is the cookie cutter and the object is the cookie, after you run the script the cookie cutter is destroyed but the cookie remains.

To get around this for testing you can put the class in a function and then call the function to create new instances of the class like below:

Function New-ReportTable{
   Class ReportTable
   {
      [String]$Title
      [String]$Description
      [ValidateSet("Error","Warning","Information")][String]$EntryType
      $Object
      [ValidateRange(0,100)][Int]$Order
      [ValidateSet("Table","List")][String]$As

      ReportTable([string]$newTitle, [String]$newDescription,[String]$newEntryType,$newObject,[Int]$newOrder,[String]$newAs)
      {
         $this.Title = $newTitle;
         $this.Description = $newDescription;
         $this.EntryType = $newEntryType;
         $this.Object = $newObject;
         $this.Order = $newOrder;
         $this.As = $newAs;
      }
      ReportTable([string]$_title, [String]$_description,[String]$_entryType,[Psobject]$_object,[Int]$_order)
      {
         $this.Title = $_title;
         $this.Description = $_description;
         $this.EntryType = $_entryType; 
         $this.Object = $_object;
         $this.Order = $_order;
         $this.As = "Table";
      }
      ReportTable(){}

      [void]ToHtml()
      {
         $this.Object = ConvertTo-Html -InputObject $this.Object -Fragment
      }
      [void]AddOrder([int]$_add)
      {
         $this.Order += $_add;
      }
      [void]SubtractOrder([int]$_subtract)
      {
         $this.Order -= $_subtract;
      }
      [void]AddOrder()
      {
        $this.Order += 1;
      }
      [void]SubtractOrder()
      {
         $this.Order -= 1;
     }
   }
   return [ReportTable]::new()
}

You can then make new empty versions of this class by casting the function into a new variable.

$A = New-ReportTable

Hopefully this has all made sense, just remember that some, all or none of this might change in any future release as PowerShell 5 is still in preview, but hopefully this should start you off in how to work with classes.

PowerShell ISE + TFS

For a while now I have been using a combination of ISE and Visual Studio to maintain my powershell scripts. Why? because I wanted to be able to have proper version control for my team and also have the features supplied by ISE.

Enter Visual Studio Team Foundation Server 2013 Update 2 Power Tools. They come with a PSSnapin to maintain files on TFS. The Scripting Guys have a great detailed blog on TFS and the PowerShell SnapIn here.

Please note that 2013 is now available and the process is very much the same. In brief, you can signup for a free TFS service via Visual Studio Online. Then Install the TFS 2013 Client. Configure the client. Install Power Tools for TFS 2013.

Now you have got TFS, ISE and a bunch of cmdlets, you might be wondering, is this really going to be easier than managing it via the VS gui? Well with a few customizations to my ISE profile and it will be.

After installing the TFS Power Tools, add the following to your ISE profile. (Just modify the $Global:WorkspacePath Variable to suit your environment).

This will make sure you have the latest files from TFS each time you load ISE, and will add a menu under add-ons where you can check-out the current file, and check-in all pending files.

Stay posted as I will publish a standalone module for easier installation soon.

$Global:WorkspacePath = 'Path/to/VS/Workspace'
Add-Type -AssemblyName System.Windows.Forms
Add-PSSnapin -Name Microsoft.TeamFoundation.PowerShell

function Checkin-Files
{
    Add-TfsPendingChange -Add -Item $Global:WorkspacePath -Recurse
    $pendingFiles = Get-TfsPendingChange -Item $Global:WorkspacePath -Recurse
    if ($pendingFiles -ne $null)
    {
        $TFSCheck = [System.Windows.Forms.MessageBox]::Show(($pendingFiles | Select-Object -ExpandProperty localitem),'Do you want to check in these files?', 'TFS Check in','YesNo')
        if ($TFSCheck -eq 'Yes') 
        {
            $TFSResult = New-TfsChangeset -Item $Global:WorkspacePath -Recurse 
            if ($TFSResult -ne $null){
            $null = [System.Windows.Forms.MessageBox]::Show(('Change Set ID: ' + $TFSResult.ChangesetID + "`r`nOwner: " + $TFSResult.Owner + "`r`nCreation Date: " + $TFSResult.CreationDate), 'TFS Check in')
            }
            else
            {$null = [System.Windows.Forms.MessageBox]::Show('No changes to check in!', 'TFS Check in')}
        }
    }
    else
    {
        $null = [System.Windows.Forms.MessageBox]::Show('No files to be checked in!', 'TFS Check in')
    }
}

Write-Host
Write-Host -Object 'Updating TFS Workspace' -ForegroundColor Green
Update-TfsWorkspace -Item 'C:\Users\Peter\Documents\Visual Studio 2013\Workspace - Techpath\TechPath Base Class Library\TPBCL' -Recurse
Write-Host
New-Alias -Name 'cf' -Value Checkin-Files
$tfsRoot = $psISE.CurrentPowerShellTab.AddOnsMenu.Submenus.Add('Team Foundation Server',$null,$null) 
$tfsRoot.Submenus.Add('Check out current file',  
    {
        $TFSResult = Add-TfsPendingChange -Edit -Item $psISE.CurrentFile.FullPath | Select-Object -Property Version, ChangeType, ServerItem
        if ($result -ne $null)
        {
            $null = [System.Windows.Forms.MessageBox]::Show(('Version: ' + $TFSResult.Version + "`r`nChangeType: " + $TFSResult.ChangeType + "`r`nFile: " + $TFSResult.ServerItem), 'TFS File Checkout')
        }
        else 
        {
            $null = [System.Windows.Forms.MessageBox]::Show('File could not be checked out', 'TFS File Checkout')
        }
    }
, 'Ctrl+Alt+E') | Out-Null
$tfsRoot.SubMenus.Add('Check in Pending Changes',  
    {
        Checkin-Files
    }
, 'Ctrl+Alt+S') | Out-Null

PowerShell: Customising the pipeline inputs

Sometime when using cmdlets there might be cases where you would assume two cmdlets would work together naturally and they just don’t. A good example of this is anything that takes -ComputerName as an input parameter (E.g test-connection) and the Get-ADComputer command.

In this example if you run Get-ADComputer -filter * you get a list of all computers in the current domain, say you now want to run Test-Connection to check machines are online, you might think you could just go:
Get-ADComputer -filter * | test-connection
Unfortunately you will be greeted with a wall of red text, this is because Get-ADComputer does not output an object with a ComputerName property, instead it has either Name or DNSHostName. You might now decide to output it all to a text file and ping them manually but your using PowerShell and there are easy ways do do this on the fly.

Method 1: Create a custom property on the ADComputer object with the name “ComputerName” so the next command receives what it expects:

Get-ADComputer -Filter * | 
   select @{n="ComputerName"; e={$_.DNSHostName}} | 
   Test-Connection

Method 2: Specify the name of the ADComputer object’s property in the next cmdlets input:

Get-ADComputer -Filter * | Test-Connection -ComputerName {$_.DNSHostName}

Using either of the above methods works with any cmdlet that accepts ComputerName as a pipeline input parameter.

Holy Trinity of PowerShell

The three most important cmdlets to remember in PowerShell, in fact the old ones you really need to remember are: Get-Command, Get-Help and Get-Member

Get-Command will give you a list of all installed cmdlets in PowerShell as well as their type, version and source. Additionally it has parameters for -verb or -noun so you can get a full list of all “Get-” cmdlets by typing: get-command -verb get or a list of all cmdlets that deal with services by typing: get-command -noun service

Get-Help is used once you know the command you are after, but you want to know more about how it works or what inputs or output to expect. You can provide some handy parameters to the get-help cmdlet such as -full to show the full help with examples, -showwindow to show the full help output in a searchable windows forms interface or -online to show the full detailed help on the technet website.

Get-Member is by far the cmdlet that I use the most, it gives you any methods and properties the current object in the pipeline has as well as specifying the type of the object your dealing with. This includes any properties that may not be visible by just outputting the object to the screen.

A notable gotcha for this is that if your passing get-member an array of strings (or any collection of any objects) it will give you the properties and methods of a string not an array. To determine if you are dealing with an array use the .gettype() .NET method.

Example:
PS C:\> $a = "Hello World"
PS C:\> $b = "hello", "world" 

PS C:\> $a | Get-Member
TypeName: System.String ..

PS C:\> $b | Get-Member
TypeName: System.String ...

PS C:\> $a.GetType() | select name, basetype
Name        BaseType 
String      System.Object

PS C:\> $b.GetType() | select name, basetype
Name        BaseType 
Object[]    System.Array