365 AD Group Licensing

27 May, 2016

small script I wrote to set users 365 licenses based on Active Directory group membership, only tested in a hybrid environment.

function grantGroupLicense($group, $license){
    $members = Get-ADGroupMember $group -Recursive
    
    foreach($member in $members){
        $adUser = get-aduser $member.samaccountname | select userprincipalname
        $msolUser = Get-MsolUser -UserPrincipalName $adUser.userPrincipalName
        grantLicense $msolUser $license
    }

    function checkLicense($user, $license){
        foreach($lic in $user.licenses){
            if($lic.AccountSku.SkuPartNumber -eq $license){return $true}
        }
        return $false
    }

    function grantLicense($msolUser, $license){
        if(-not(checkLicense $msolUser $license)){
            try{
                set-msolUserLicense -userprincipalname $msolUser.userPrincipalName -AddLicenses $license -ErrorAction Stop
                write-host $msolUser.userPrincipalName Has been given $license -ForegroundColor green
            }catch{
                write-host $msolUser.userPrincipalName could not be given $license -ForegroundColor red
            }
        }else{
            write-host $msolUser.userPrincipalName already has $license -ForegroundColor green
        }
    }
}

Usage:
grantGroupLicense <AD-Group-Name> <License SkuPartNumber>

eg:
grantGroupLicense FG-MSVisio_Users VISIOCLIENT
grantGroupLicense FG-MSProject_Users PROJECTCLIENT

 

 

PowerShell Mindflash Administration

04 April, 2016

Having a position where part of my job is to administrate users within Mindflash I am frequently completing the following tasks on Mindflash:
• Creating Users
• Enrolling users in courses
• Resetting user passwords

Often these tasks need to be completed for either an individual user or a batch of users at any given time. While Mindflash provides some bulk administration options through their web portal I found it a little limiting and a little clunky to use.

So naturally been a fan on the command line and primarily a Linux user I thought it would be great to be able to administer Mindflash users from a command line, In this case PowerShell. I have created Get-MindflashUser, A PowerShell cmdlet that hooks into the Mindflash API allowing for administration of users.

Get-MindflashUser allows you to complete all of the following tasks without ever leaving the PowerShell window.
• Get a list of all Mindflash users
• Get a list of all Mindflash courses
• Get a list of all users in a specific course
• Get a specific users details
• Get a specific users details including course enrolment details
• Get course progress for a given user and course
• Invite users to a course
• Reset user password
• Create new users

In addition to all of this, you would obviously be able to use Get-MindflashUser within you own scripts to automate repetitive tasks or generate reports.

Some Examples of Use
Resetting a users password

get-MindflashUser -email user@email.com -resetPassword true -newPassword P@ssword21 –Key <yourAPIKeyHere>

Creating a new user

get-MindflashUser -email user@email.com -first michael -last cho -newUser true -newPassword P@ssword21 –Key <yourAPIKeyHere>

There are more examples of user provided in the header of the script. If you find this script useful in any way please let me know by email at Nathan.kewley@gmail.com. Additionally if you find any issues or bugs in the script please shout out so I can resolve them.

 

Download Get-MindflashUser.ps1

 

Creative Commons License
Get-MindflashUser by Nathan Kewley is licensed under a Creative Commons Attribution 4.0 International License

 

Playing around with IIS and Powershell

01 April, 2016

Playing around with IIS, .NET and PowerShell, more specifically how to execute PowerShell from a form on a webpage. It turns out actually invoking some PowerShell on server side via a client request is quite easy. Here I am hoping to show an example of the minimum code required to achieve this.

We will create a simple interface like the one below. The button to run code will invoke a PowerShell command on the server. The result of the PowerShell command will be appended to the text box below the button.

undefined

The command I am using for testing this with is:

$(Get-WmiObject Win32_Computersystem).name

This command will query the pc for its hostname and return it. So after pressing the button the server will run this command and print the result in the text box. The webpage should now look like this.

undefined

Only 2 files are required to achieve this, I have chosen to use C# to create this. The .html file required is:

<%@ Page Language="C#" AutoEventWireup="true" CodeBehind="test.aspx.cs" Inherits="powerWeb.test" %>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">

<html>
    <head id="Head1" runat="server">
        <title>c# iis powersehll</title>
    </head>

    <body>
        <form id="form1" runat="server">
            <asp:Button ID="resetButton" runat="server" Width="308" Text="Run Code" onClick="runCode" /><br />

            <!-- Holds the result of the command -->
            <asp:TextBox ID="response" TextMode="MultiLine" Width="600" Height="200" runat="server"></asp:TextBox><br />
        </form>
    </body>
</html>

And the .aspx.cs file required that goes along with the html is is:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.Web.UI;
using System.Web.UI.WebControls;
using System.Management.Automation;

namespace powerWeb
{
    public partial class test : System.Web.UI.Page
    {
        //function that runs when the button is pressed
        protected void runCode(object sender, EventArgs e)
        {
            //create the powershell instance and give it the command we will be executing
            var shell = PowerShell.Create();

            //build out query string
            string query = "$(Get-WmiObject Win32_Computersystem).name";

            //add the command specified from the gui
            shell.Commands.AddScript(query);

            //execute the command and store resutls in results
            var results = shell.Invoke();

            //for each item in the results we append it ot the response text box on the webpage
            foreach (PSObject result in results)
            {
                response.Text = Server.HtmlEncode(result.BaseObject.ToString());
            }
        }

    }
}

Note that you may need to use package manager to install 'System.Management.Automation' as detailed here: https://www.nuget.org/packages/System.Management.Automation

 

Like stated before the point of this is to provide a minimum example of how to execute PowerShell from IIS and .NET. I plan to expand on this concept to allow some PowerShell to ad automation. So I might get around to posting more on here if I have success with this.

Building a Crappy Rest API in PHP

01 April, 2016

So I got bored and decided it would be a good idea to build a Rest API for my website crappypuns.com. Having only briefly worked with Rest API’s once before I have no doubt that the API I have ended up building is not the best. It is however a simple to implement and understand API so could serve as a good starting point for working with or building API’s. The API and documentation for it are available at http://crappypuns.com/about.php.

The process for creating the API was surprisingly easy and required only two PHP files to create as there are only two commands exposed, one to query for puns and the other to query for images. Each query supports a common parameter ‘limit’ which specifies how many results should be returned up to a maximum of 20.

For the sake of simplicity I will focus only on http://crappypuns.com/api/api_pun.php which is the API link to get jokes. You can choose how many jokes you want returned from the server using the limit parameter like: http://crappypuns.com/api/api_pun.php?limit=10 will return 10 puns in JSON format.

The code that runs on the server when the API call is made is as follows (with minor tweaks for security).

<?php               
        //This is the function that will query the database for the puns
        function getPuns($connect, $limit){                                            
                //Get the amount of jokes required randomly from the database using fake sql parametrs for this example  
                $joke = mysqli_query($connect, "SELECT `punField`,`punIdField` FROM punTable ORDER BY RAND() LIMIT $limit");
                                                                      
                //fetch each result that was returned               
                while($row = mysqli_fetch_assoc($joke)){                 
                        //Append the data to $output               
                        $output[]=$row;                   
                }                                  
                //return the puns pulled from the databse       
                return $output;                    
        }                                             
                                                    
        //See if a limit parameter is set. If not set the limit to 1       
        if (isset($_GET['limit'])){                       
                $limit = $_GET['limit'];               
        }else{$limit = 1;}                      
                                                               
        //make sure limit does not exceed max of 20           
        if($limit > 20){$limit = 20;}                       
                                                         
        //Establish a connection to the database     
        $connect = mysqli_connect('server', 'usrname', 'password', 'database');
        
        //Get the punss from the database                                 
        $jokes = getPuns($connect, $limit);                         
                                                                               
        //Return the results in json format                                 
        print(json_encode($jokes, JSON_UNESCAPED_SLASHES));                  
?> 

I think this is probably the most simple an API can get. Ideally you would expand on this by having some form of security in place like a validation key required to make requests. Maybe a limit on how many requests a client can make in a given time frame.

Restoring Enterprise Vault Items From 365

31 March, 2016

Restoring items from Enterprise Vault for 365 users is the single most painful thing I have ever had to do in my life… EV is literally the devil. So hopefully by documenting the method I used to restore these Items I can save someone from many a sleepless night. The basis of this problem is that once a user has been migrated to the 365 exchange the Enterprise Vault server can no longer see the users mailbox and thus is unable to restore vaulted items.

In order to restore the items to the user’s mailbox the vaulted items need to be recovered to an on-prem account, restored and then returned to the mailbox. The method I used to achieve this is as follows.


1. Extract the vaulted items from the users mailbox
Extracting the vaulted items is probably the most difficult task as you want to extract only the items that are vaulted while maintaining the folder structure that the user has in their outlook. The first think to do is get full access to the user’s mailbox. This can be don’t from portal.office.com > admin > exchange > mailboxes. There are guides all over google for how to do this if you get stuck ;)

Once you have granted yourself full access to the user’s mailbox you will need to start outlook on your machine and create a new profile. Fill out the name and email address fields with the users details, make sure to leave the password field blank.

undefined

Upon hitting next you will be asked for credentials, put your credentials in here as you should have access to the user’s mailbox. Make sure to tick the ‘remember my credentials’ box. Outlook should then open to the user’s mailbox. You will need to go into mailbox settings and set outlook to cache the whole mailbox offline.

undefined

You will need to restart outlook and wait for it to cache the mailbox, this could take a while depending on the size of the mailbox. We cache the whole mailbox because only cached items are picked up when we scan the mailbox for vaulted items.

I wrote a PowerShell script that scans the current mailbox for vaulted items and makes a copy of them to ‘c:/vaultedmail’ while retaining folder structure. Running this script could take a while if the mailbox is large. The script will also generate some logs to help diagnose errors, these logs are stored at ‘c:/scans/’.

#script written by Nathan Kewley 2015

#file path saving output
$emailPathLog = "c:\Scans\emailFiles.csv";

#initial script setup
$ol = new-object -com Outlook.Application
$ns = $ol.GetNamespace("MAPI")

#variables to keep track of current folder to keep folder structure in tact
$masterDir = "c:\vaultedmail\" + $ol.Application.DefaultProfileName  + "\";
$currentDir = "c:\vaultedmail\" + $ol.Application.DefaultProfileName  + "\";

#counter so emails are not overwritten
$counter = 0;

#get the vault folder
$vault = $namespace.Folders | ?{$_.name -match "Inbox"}

#check if the email is vaulted, if so move it to the local drive keeping folder structure in tact
function checkMail($mail){
    if($mail.body -like "*has been archived*"){
        write-host("Vaulted Item Detected" + $counter);
        $filename = $currentDir + "mail" + $counter + ".msg";
        $mail.SaveAs($filename);
        $filename >> $emailPathLog;
    }
}

#recursivly scan all items and subfolders in users mailbox
function Get-MailboxFolder($folder){
    write-host $folder.name, $folder.items.count

    #create directory for the folder
    $path = $currentDir + $folder.name + "\";
    New-Item -ItemType directory -Path $path;
    $currentDir = $path;

    foreach($mail in $folder.items){
        $counter++;
        checkMail($mail);
    }

    foreach ($f in $folder.folders){
        Get-MailboxFolder $f
    }
}

#start a transcript
Start-Transcript -Path "c:\Scans\log.txt";

#initial script setup
$ol = new-object -com Outlook.Application
$ns = $ol.GetNamespace("MAPI")
$mailbox = $ns.stores | where {$_.ExchangeStoreType -eq 0}
$mailbox.GetRootFolder().folders | foreach { Get-MailboxFolder $_}

When the script has finished you will have extracted all the vaulted items from the users mailbox (Note: there is a small error margin for some mailboxes).

2. Get the vaulted Items back on prem
You will need to use your ‘vault service account’ or alternatively any other account that has permissions to restore any items from the vault. Log into a pc using your ‘vault service account’ and start outlook. You will need to copy the folder structure containing the vaulted items to this pc. To import this folder structure into outlook I used a third party tool called ‘msg to pst’, it seems to work ok. Use ‘msg to pst’ on the folder structure and it will import it into the ‘vault service account’ mailbox. It might be an idea to change the name of the imported folder to the name of the end user. Note that this tool will append the title text of the emails with something like ‘msg to pst trial version’. Don’t worry about this, this text will disappear when the vaulted item is restored.

3. Restore the vaulted items.
You should be able to restore the vaulted items from the ‘vault service account’ mailbox using the EV add in just like normal. Easy! :) Once you have un-vaulted all the items export the folder from outlook as a .pst

4. Return the items to the end user
You will need to open up outlook to the users mailbox using the profile you created for them earlier. Once back in their mailbox you will need to do an import from the pst using outlooks inbuilt import/export wizard. When importing you will need to match up the ‘inbox’ folder in the pst to the ‘inbox’ folder in the mailbox. You may need to do multiple imports from the pst if there were vaulted items in other folders like ‘sent items’.

undefined

Once you have imported all the items the user will have 2 versions of every vaulted email in their mailbox, one that is vaulted and one that you have restored. The last step to completing the restoration is to remove all the vaulted stubs. You can search the whole mailbox with the search term ‘messageclass:ipm.note.enterprisevault’ which will show you all the vaulted items. Then select all, delete. Done!

Also, don’t forget to remove your permissions from the users mailbox once you are done.

HTML5 Local Storage

31 March, 2016

Local storage allows the developer of a HTML5 webpage or app to store data locally on the client’s machine. Data stored in local storage will be persistent across browser and computer restarts. Local storage also has the bonus of being super easy to write to and read from. I have primarily being using local storage as part of a HTML5 game to store highscore, current Level and various other values that I want stored across sessions.

var saveData = {
	unlockLevel: 0,
	endlessHighScore: 0,
	goldCoins: 0
}

I hold all the data that I want to save in a single JavaScript struct so I am able to save all the data I want easily. By trying to load the data I can check if it already exists, If it does not exist I can save the initial values to the local storage. Notice that the data to be stored needs to be ‘stringified’. And data loaded needs to be ‘parsed’. The code below is what I am using in my upcoming Phaser game to save and load Game data to the local storage.

if(!localStorage.getItem("saveData")){
	localStorage.setItem("saveData", JSON.stringify(saveData));
	console.log("Could not load data, data store created")
}else{
	saveData = JSON.parse(localStorage.getItem("saveData"));
	console.log("Loaded Data")
}

 

Newer posts → Home