Showing posts with label scripts. Show all posts
Showing posts with label scripts. Show all posts

Friday, 30 September 2016

Get Last Windows Operating System Boot Time using Powershell

We can easily use powershell to query a computer to retrieve the time and date that windows last booted/started up.

We run a get-wmiobject query to retrieve the properties from the win32_operatingsystem class and store the results into the $osprops variable. We then run to ConvertToDateTime method on the LastBootUpTime property to return the result and store it in the $lastboot variable

$osprops = get-wmiobject -class win32_operatingsystem 
$lastboot = $osprops.ConvertToDateTime($osprops.LastBootUpTime)

The $lastboot variable will then provide an output like below;



This variable can be parsed through different methods to change the output to a different format. you can view all the different methods available by running $lastboot | get-member

Some examples.

$lastboot.ToShortDateString() will return the above date in the format of mm/dd/yyyy
$lastboot.DayOfWeek will only return the day of the week (eg. Monday, Tuesday, etc)

Tuesday, 27 September 2016

Querying/Checking Windows Event Viewer Logs with Powershell

Powershell has a cmdlet you can use to check/query the windows event log.  You can customize this cmdlet in several ways to refine the information that is returned.

For example, you can use the -after switch to only return event log entries after a certain date - such as events only returned within the past 1 day (24 hours)

You can also filter the type of entries that are returned. An example would be to only return warning or error entries, and ignore any "informational" type entries

Let's start with the basic command;

get-eventlog -logname "Application"

This command will return all entries within the Application log, which will usually be alot, and not very useful. You can also use "System" or "Security" as other default logs.

Let's refine the command further, to only return entries for the past day. To do this we will define the current date into the $date variable, and subtract one day from that value

$date = get-date
$date = $date.adddays(-1)

We can now use this $date variable to return all event log entries AFTER this date (using the -after switch)

get-eventlog -logname "Application" -after $date

The script will now return ALL events from the Application log from the past 24 hours. Let's refine it a bit further and filter the results so only Warning and Errors are returned

get-eventlog -logname "Application" -after $date | where-object {$_.entrytype -ne "Information"}

Of course you can store the results into a variable so it can be further queried using subsequent commands;

$events = get-eventlog -logname "Application" -after $date | where-object {$_.entrytype -ne "Information"}

Friday, 16 September 2016

Export/Audit All Exchange ActiveSync Devices using Powershell

Below are a couple of commands we can use in Windows Powershell to run a report on all mobile devices that have been synced with mailboxes within your exchange environment.

First step is to gather a list of users that have an ActiveSync Device partnership

$userlist = gt-casmailbox -filter {hasactivesyncdevicepartnership -eq $true -and -not displayname -like "CAS_{*"} | Get-Mailbox

This list of users is then used against the Get-ActiveSyncDeviceStatistics cmdlet to retrieve the associated ActiveSync devices with each users mailbox. We then select certain fields to reduce the amount of data and present it in the $report variable.

$report = $UserList | foreach { Get-ActiveSyncDeviceStatistics -Mailbox $_} | select Identity, LastSuccessSync, DeviceType, Status

You can also add the export-csv component onto the end of the command to export the $report contents to a .csv file

$report = $UserList | foreach { Get-ActiveSyncDeviceStatistics -Mailbox $_} | select Identity, LastSuccessSync, DeviceType, Status | export-csv -path "C:\ActiveSyncDevices.csv" -notype

Thursday, 15 September 2016

View and Change Exchange Mailbox Calendar Permissions with Powershell

Permissions for mailbox calendars are managed separately to the actual mailbox permissions. You can use the below cmdlets in powershell to view and add/edit the permissions on a users mailbox.

To view current calendar permissions on a mailbox

get-mailboxfolderpermission -identity "name:\Calendar" | ft

To add new calendar permissions on a mailbox

add-mailboxpermission -identity "name:\Calendar" -User "usertogetaccess" -AccessRights "Accesslevel"


To modify an existing calendar permissions entry on a mailbox

set-mailboxfolderpermission -identity "name:\Calendar" -User "usertogetaccess" -AccessRights "Accesslevel"

To remove an existing calendar permissions entry on a mailbox

remove-mailboxpermission -identity "name:\Calendar" -User "usertogetaccess" -AccessRights "Accesslevel"

Name = the display name alias or email address you are setting the calendar permissions ON
Usertogetaccess = the display name, alias or email address you are granting calendar permissions TO
Accesslevel = the level of access to be granted. The available options are:
  • Owner
  • Publishing Editor
  • Editor
  • Publishing Author
  • Author
  • Nonediting Author
  • Review
  • Contributor
  • Free/Busy Time
  • None

Wednesday, 14 September 2016

Check which Exchange Mailboxes a User has Full Access or Send As Permissions On using Powershell

As an exchange administrator, you may occassionally need to know which mailboxes a particular user has Full Mailbox Access or Send As permissions to. This may be required as part of an audit, or to simply copy an existing users permissions for a new user you are setting up/creating.

The script below helps to accomplish this, as there is no in-built/easy way to view which mailboxes a particular user has access to - ie. Full Mailbox Access, or Send As permissions

First you need to specify the user whose existing access we are checking, using the $user variable. We use the wildcard "*" to essentially match any name that contains what is between the *'s - the users first name, last name or alias should work.

$user = "*peter*"

Next we run the get-mailbox cmdlet against all mailboxes in exchange, to query the permissions on each mailbox to see if this user exists in the respective permissions list.

There are two separate commands to do this - one to check for Full Access permissions, and the other to check for Send As permissions

get-mailbox -resultsize unlimited | get-mailboxpermission | where {$_.user -like $user} | select Identity, AccessRights

get-mailbox -resultsize unlimited | get-adpermission | where {($_.user -like $user) -and ($_.ExtendedRights -like "*Send-As*")} | select Identity, ExtendedRights

If any matches are found, the results will be displayed showing their Identity (ie. name) and the Access Rights level they have

Friday, 9 September 2016

Get ActiveSync Enabled Accounts/Mailboxes using Powershell

Here is a short/simple script you can use to obtain a list of all mailboxes within your Exchange environment that have the ActiveSync service enabled on them.

#Add Exchange Cmdlets
add-pssnapin *exchange* -erroraction SilentlyContinue

get-casmailbox -resultsize unlimited | where {$_.ActiveSyncEnabled -eq $true}

The output will now be displayed showing all mailboxes in your environment that have ActiveSync functionality enabled on them.

You can export your results to a .csv by adding a bit more to the end of the command as per below. You can of course change the output path as required

get-casmailbox -resultsize unlimited | where {$_.ActiveSyncEnabled -eq $true} | select Name, ActiveSyncEnabled | export-csv "C:\activesyncusers.csv" -notype

Friday, 28 March 2014

Check/Monitor Website URL with Powershell

Windows Powershell has a built in web request module that you can use to test/check the availability of website URL(s).

The full script to do this is below;

[string] $url = "http://www.google.com"
[net.httpWebRequest] $req = [net.webRequest]::create($url)
$req.method = "HEAD"
[net.httpWebResponse] $res = $req.getresponse()

The first line is self explanatory - simply put in the full URL for the website you wish to check. In this example we will be checking http://www.google.com

[string] $url = "http://www.google.com"

The second line is where we create the actual web request instance in Powershell - under the $req variable

[net.httpWebRequest] $req = [net.webRequest]::create($url)

On the third line, we change the request method to be "HEAD" which means that only header information for the requested URL is retrieved. This speeds up the web request process as it does not pull all the data from the web URL - only the header information. If you leave this line out, the default method is "GET".

$req.method = "HEAD"

On the last line we actually submit the web request, and store the response in the $res variable

[net.httpWebResponse] $res = $req.getresponse()

For a successful web request, the response should look something like this:

IsMutuallyAuthenticated : False
Cookies                 : {}
Headers                 : {Cache-Control, Content-Type, Date, Expires...}
ContentLength           : -1
ContentEncoding         : 
ContentType             : text/html; charset=ISO-8859-1
CharacterSet            : ISO-8859-1
Server                  : gws
LastModified            : 28/03/2014 10:24:19 AM
StatusCode              : OK
StatusDescription       : OK
ProtocolVersion         : 1.1
ResponseUri             : http://www.google.com.au/?gfe_rd=cr&ei=I7M0U5P_BenC8gfRvIHADg
Method                  : HEAD
IsFromCache             : False

Based on this, you could check the statuscode or statusdescription properties of $res to make sure the value matches "OK".

Alternatively, if you enter an invalid URL for a website that doesn't exist, you will get an error, and the value of $res will be $null. The error you get will be something along the lines of;

Exception calling "GetResponse" with "0" argument(s): "The remote server returned an error: (502) Bad Gateway."
At line:4 char:46
+ [net.httpWebResponse] $res = $req.getresponse <<<< ()
    + CategoryInfo          : NotSpecified: (:) [], MethodInvocationException
    + FullyQualifiedErrorId : DotNetMethodException

Wednesday, 26 March 2014

Get Folder Size (including subfolders) with Powershell

The method for obtaining the size of all items within a folder using Windows Powershell is unfortunately not as straight forward as it probably should be. The method outlined below is very useful for querying multiple folders to determine the size of all items inside, including all subfolders and files.

$dir = "C:\temp"
$totaldirsize = (get-childitem $dir -recurse -force | measure-object -property length -sum)

The first variable sets the directory that we wish to query - in this example it is C:\temp.

Next, we use a get-childitem to query the directory. The -recurse and -force switches mean that all sub directories and files are also included. We then pipe the results to measure-object and calculate the length of each child item (which is actually the size in bytes) and use the -sum switch to add them all up.

If you run the above command, and then look at the $totaldirsize variable, you will see something like below;

PS C:\> $totaldirsize

Count    : 38
Average  : 
Sum      : 51652089
Maximum  : 
Minimum  : 

Property : length

So from this we can see there are 38 items in total in the C:\temp directory, and the sum of all files is 51652089 bytes. To make this more useful, we can easily convert this value to KB, MB or GB

$mbsize = $totaldirsize.sum / 1MB

If we now look at $mbsize, we'll usually have an integer with a large number of decimal places. In this example, the result I got was 49.2592706680298. So as a final step, I'd like to round this number to 2 decimal places

$mbsize2 = "{0:N2}" -f $mbsize

Now if we look at the value of $mbsize2, the result is 49.26.

You can change the 2 in {0:N2} to any other digit to round the number to that many places after the decimal point.

Working with Windows Services in Powershell

We can use the get-wmiobject method in order to retrieve properties of windows services on local or remote servers.

The query below is an example on how to get the properties of the Print Spooler service on a local machine (ie. the same machine that the script is being executed on)

To get the "Service Name" of a windows service, go to services.msc, select a service, open it's properties (right click > Properties) and look at the "Service Name" at the top. 

$serviceprops = get-wmiobject -class win32_service -filter "name='Spooler'"

If we then run $serviceprops we get the following information;

ExitCode  : 0
Name      : Spooler
ProcessId : 1628
StartMode : Auto
State     : Running

Status    : OK

This information could therefore be used to check the respective windows process ID, start mode, state and status of a service

The query below is an example on how to get the properties of the Print Spooler service on a remote machine (server1)

$serviceprops = get-wmiobject -computername "server1" -class win32_service -filter "name='Spooler'"

As you can see, the command is mostly the same, we have simply added the argument "-computername "server1"" to make the get-wmiobject query run on the remote server.

We can then take this one step further and perform an action (aka method) on a service, such as starting or stopping it. To view the available methods for the service, run a get-member on the $serviceprops variable;

$serviceprops | get-member

You will then see a list of available methods (and properties) for the variable.

Two of the most common methods for a service would be to start or stop the service. We simply append the respective methods onto the end of the $serviceprops variable (after it has run the get-wmiobject query above to get the service properties).

To start a service;
$serviceprops.startservice()

To stop a service;
$serviceprops.stopservice()

Friday, 3 May 2013

Adding Multiple Users to 'Accept Messages Only From' - Exchange 2007

Exchange 2007 has a feature that allows restrictions to be placed on a distribution group (I call them "distribution lists", or "DL's") that control who is allowed/permitted to send messages to them.

The Exchange Management Console enables you to search and add individual users to this list, but I found the process can be very slow and tedious, especially if you want to add a large number of users to this list, or want to add users to multiple DL's.

For this reason, I created the below script. Others who may have tried this using a simple "Set-DistributionGroup" command would have found that every time they tried to add a user it replaced any users who were already in the list. This script queries the already existing users and appends/adds the new user onto the already existing list. You will need to provide a list of users either within the script, or by importing a simple .txt file with a list of users you wish to add. For this example, I will use a .txt file.

The .txt file contains a simple list of users with a single name on each line;

firstname.lastname@domain.com
test.user1@domain.com
example.user2@domain.com

And here is the script:

#Name of Distribution Group/List to add user(s) to
$TargetDL = "DL_Test"

#Domain Controller Name - must be used to ensure each user is appended and not replaced. 
$DC = "domaincontrollername"

#Import List of Users to add from .txt file
$UserListFile = "C:\UserList.txt"
$UserList = Get-Content $UserListFile

#Cycle through list of users and add them to 'Accept Messages Only From' list for DL
ForEach ($User in $UserList)
     {
     Set-DistributionGroup "$TargetDL" -AcceptMessagesOnlyFrom ((Get-DistributionGroup -DomainController "$DC" -identity "$TargetDL").AcceptMessagesOnlyFrom + "$User") -DomainController "$DC"
     Write-Host "$User granted permission to send to $TargetDL"
     }


Replace the $TargetDL, $DC, and $UserListFile variables with the relevant information for your Exchange environment

Friday, 8 February 2013

Querying Exchange Mailboxes with Powershell Pt 2

In my previous blog post, I outlined some methods to query Exchange mailboxes using the get-mailbox cmdlet. Whilst the information obtained using this cmdlet is very useful, it does not contain all the information that is available for an Exchange mailbox.

There is another cmdlet available called Get-MailboxStatistics. It is used/applied in the same way as the Get-Mailbox cmdlet, but contains different fields or properties, and therefore, different information relating to the mailbox.

If you run the command Get-MailboxStatistics -identity "MailboxName" | fl it will display the mailbox statistics for that particular mailbox.

This information includes;

  • Associated item count (ie. number of items within the mailbox)
  • Deleted item count
  • Last logon/logoff time
  • Total size of items
  • Total size of deleted items
So, for a practical example that you could potentially use to query this information. Let's say you want to query all your mailboxes to identify those that have more than 20,000 items within them. You could run the following command;

Get-Mailboxstatistics | Where {$_.ItemCount -gt "20000"} | Select DisplayName

You could replace $_.ItemCount with any of the other properties that are contained within the Get-MailboxStatistics cmdlet.

If you want the query to return more than just the DisplayName field for objects that match your query, you can add them after DisplayName and separate them with a comma (,), or if you want to return all properties then remove | Select DisplayName altogether.

You can also add | Export-CSV-path "C:\Export.csv" -notype to the end to export your query results to a .csv file.

Tuesday, 5 February 2013

Querying Exchange Mailboxes with Powershell

Exchange and Powershell go hand in hand - as it is essentially what Exchange is built on top of, and is what the Exchange Management Console (EMC) uses to execute commands you choose through the GUI. (Ever noticed you get the Powershell command line equivalent for commands you execute in EMC?)

One of the most common things an administrator will need to do is query all the mailboxes within the system for certain criteria, which I will explain and breakdown in this blog entry.

The command Get-Mailbox is one of the most useful and powerful commands you can use (for information gethering). It can be used to retrieve all the properties for all the mailboxes in your system, or can be tweaked to only return some of the properties for some of the mailboxes within your system.

If you execute the command Get-Mailbox on its own, you will probably be flooded with 1000 responses, followed by the following warning message;


WARNING: By default only the first 1000 items are returned. To change the number of items returned, specify the parameter "-ResultSize". To return all items specify "-ResultSize Unlimited" (Note: Returning all items may take a 
very long time and consume a large amount of memory depending on the actual number of items). It is not recommended to store the results in a variable; instead pipe the results to another task or script to perform batch changes

As per the message, the command on its own will only return the first 1000 results. You can change this by adding -ResultSize Unlimited to it, so it would look like this;

Get-Mailbox -ResultSize Unlimited

If you run this command it will run through and display the first few properties for every mailbox within your system. While this can be useful, the command can be further tweaked to run faster and provide more accurate/informative results.

To get all the properties for a single users mailbox, you can use the following command

Get-Mailbox -Identity "Morrissey, Peter"

You can replace what is between the " " with any identifier for the mailbox - such as Primary SMTP Address, Display Name or Alias.

When you run this command it will only display the first few properties as it is presenting the information in a table format. If you change the command to display in list format (by adding | fl), you get MUCH more information:

Get-Mailbox -Identity "Morrissey, Peter" | fl

Now you can view ALL the properties for an individual users mailbox. These properties apply to every mailbox within the system, so you can once again, modify the Get-Mailbox command to search on any of the properties you see in this list.

For example, if I wanted to query all the mailboxes within my system, and only return those whose 'Name' property contain the text "Peter", I would run the following command

Get-Mailbox -ResultSize Unlimited | Where {$_.Name -like "*Peter*"}

You still need to include -Resultsize Unlimited because although you aren't expecting more than 1000 results to be returned, you do want the Get-Mailbox command to query more than the first 1000 mailboxes, which it will not do if this omitted.

You can replace the $_.Name with any of the other properties for a mailbox - it just needs to have the $_. before it.

The -like operator can also be changed to use -eq (equal to) -ne (not equal to) -gt (greater than) -lt (less than) -le (less than or equal to) -ge (greater than or equal to)

Next you can fine tune the properties that you wish to display for each object whos name contains "Peter". Say you want to only display the DisplayName, Alias, Database and PrimarySMTPAddress properties for each of the results. You could use the following line

Get-Mailbox -ResultSize Unlimited | Where {$_.Name -like "*Peter*"} | Select DisplayName, Alias, Database, PrimarySMTPAddress

The benefit of doing this is that by retrieving fewer properties for each object, it speeds up the time it takes for the query to run. It also makes looking through the results much faster as you aren't reading over information you don't need. Once again, you can replace the properties I used with any of the properties available for each mailbox, as we discovered earlier.

Finally, you  can export the results of your query to a CSV file

Get-Mailbox -ResultSize Unlimited | Where {$_.Name -like "*Peter*"} | Select DisplayName, Alias, Database, PrimarySMTPAddress | Export-CSV -path "C:\Export.csv" -notype

Once you have the information in a CSV file you can attach it to an email and send it to yourself (or someone else) as per my previous blog post

Creating Custom Tables in Powershell

When working with scripts, it is often necessary to collect, store and present information in a table format. An example of this could be to export a number of properties from a users mailbox in Exchange into a table format.

For my example, I will run the following command to export all the properties of a mailbox (mine) to a variable called $UserList

$UserList = get-mailbox -ResultSize Unlimited | Where-Object {$_.DisplayName -eq "Morrissey, Peter"}

The next thing to do is to declare/create the table. It can be called anything you like, but I tend to use $report. The following line of code creates the table;

$report = @()

Next, you need to populate each row of your table with whatever fields you require. This would usually be done with a ForEach statement where you cycle through a list of objects, with numerous properties for each object.

In my example, the object list is stored in $UserList. I can run the command $UserList | fl to display the list of all the properties available for each object in my variable.

This ForEach command will cycle through each entry in $UserList (in my example it is only a single entry for my mailbox) and add whatever properties of that object I declare into the table (I have used DisplayName and Database) but you can use as many as you like - they just need to be separated by a semi colon (;)

ForEach ($User in $UserList)
             {
             $report += New-Object psobject -Property @{DisplayName=$($User.DisplayName);Database=$($User.Database)}
             }

This is a simple example and will create a table with two values for each row; DisplayName and Database.

Once you have populated all the rows you require in your table, you can then export it to a CSV file using the following command;

$report | select DisplayName, Database | Export-CSV -path "C:\ReportOutput.csv"

Once again, you will need to replace $report with whatever variable you used to declare your table. You also need to use the Select component to select all the table fields you wish to export into the CSV file - in my case it was the DisplayName and Database fields.

Finally, once the CSV file is exported, you can then attach it to an email and send it to yourself (or someone else) as outlined in my previous blog post.

Tuesday, 29 January 2013

Sending SMTP Emails with Powershell using Authentication

The following script can be used to send an email message using SMTP. This method is slightly different to my previous post about sending email messages in Powershell as this method uses the smtpClient method rather than mailmessage in order to allow for authentication to occur.

$From = "fromaddress@domain.com"
$To = "toaddress@domain.com"
$SMTPServer = "smtp.gmail.com"
$SMTPPort = "587"
$Username = "username@gmail.com"
$Password = "gmailpassword"
$subject = "Email Subject"
$body = "Insert body text here"

$smtp = New-Object System.Net.Mail.SmtpClient($SMTPServer, $SMTPPort);

$smtp.EnableSSL = $true
$smtp.Credentials = New-Object System.Net.NetworkCredential($Username, $Password);
$smtp.Send($From, $To, $subject, $body);

You will need to update the values of the first 8 variables to match what is required for the email account/domain you are sending from.

The SMTP Server and Port number will vary for different email providers - I can confirm the server and port specified above for Gmail are correct though.

UPDATE - 29/11/13

You can also use the System.Net.Mail.MailMessage class to give you the additional option to add CC, BCC, attachments etc, as per the below script. Simply update the first 9 variables below to configure your email message.

$SMTPServer = "smtp.gmail.com"
$SMTPPort = "587"
$Username = "username@gmail.com"
$Password = ""

$to = "user1@domain.com"
$cc = "user2@domain.com"
$subject = "Email Subject"
$body = "Insert body text here"
$attachment = "C:\test.txt"

$message = New-Object System.Net.Mail.MailMessage
$message.subject = $subject
$message.body = $body
$message.to.add($to)
$message.cc.add($cc)
$message.from = $username
$message.attachments.add($attachment)

$smtp = New-Object System.Net.Mail.SmtpClient($SMTPServer, $SMTPPort);
$smtp.EnableSSL = $true
$smtp.Credentials = New-Object System.Net.NetworkCredential($Username, $Password);
$smtp.send($message)
write-host "Mail Sent"

File Locked After Sending SMTP Email with Powershell

In my previous blog post about sending emails with Powershell, I mentioned a problem where files that you attach to an email become locked until the instance of Powershell you are running has exited completely. So if you run a script through Powershell ISE that attaches a file to an email, that file will remain locked until you exit Powershell ISE.

If the file is locked by Powershell, you will get an error/warning message similar to the following if you try to modify it in any way;

The process cannot access the file 'c:\filename.txt' because it is being used by another process

By using the following command, you can ensure that Powershell 'disposes' of the email message once it has been sent and does not continue to 'lock' any files you attach and send via email;

$mailmessage.dispose()

Note: this is assuming that $MailMessage = New-Object system.net.mail.mailmessage 

Friday, 25 January 2013

Sending Email Messages with Powershell

A lot of the scripts I use generate reports or .csv files that I need to reference or send to other users who have requested them. One of the easiest ways to accomplish this is to configure your script to automatically email yourself (or anyone else) with the results and/or any files that were created in your script. This saves you time by not having to manually copy the files to another location or attach them to a new email message. You can simply receive the email message and forward it on, or include all recipients in the original email sent by the script.

The following lines of code can be used to create and send an email message with Windows Powershell:


$SmtpClient = new-object system.net.mail.smtpClient 
$MailMessage = New-Object system.net.mail.mailmessage 
$SmtpClient.Host = "your.smtp.server" 
$mailmessage.from = ("fromaddress@yourdomain.com") 

$mailmessage.Subject = “Subject”
$mailmessage.Body = "body text"
$mailmessage.IsBodyHtml = $true
$mailmessage.ReplyTo = "replytoaddress@yourdomain.com"
$mailmessage.Attachments.Add("C:\Path\yourfile.txt")
$smtpclient.Send($mailmessage)
$mailmessage.dispose()

Notes:

You will need to replace the values in some of the variables above to allow it to work in your environment (ie. SmtpClient.Host, FromAddress, Subject, Body text, Reply to address, attachment path).

You will also need to ensure that whatever machine you are running this script on is "authorised" to send with the SMTP server you have configured.

The final line of code $mailmessage.dispose() is very important when sending emails with attachments. If this line is not included, Powershell 'locks' the file(s) you attached after the message has been sent and will not 'release' them until the Powershell instance you are running is closed.

Thursday, 24 January 2013

Exporting Exchange Distribution Group Members with Powershell

Before making any major changes to distribution groups, I like to take a backup of the current membership lists prior to making any changes. Particularly in cases where membership lists are quite large, it's always better to be safe than sorry for when a user or distribution group owner wants to know who was a member prior to making the change.

Getting the list of members and exporting it to a simple .csv file can be achieved using the Powershell script below.

Note that you should change the first two (2) variables ($DLName and $ExportFilePath) accordingly.

#Script to get/export list of all distribution group members
#Date Created: 24th January, 2013
#Author: Peter Morrissey


#Enable Exchange cmdlets
add-pssnapin *exchange* -erroraction SilentlyContinue

$DLName = "DL_Example_List"
$ExportFilePath = "C:\Export\Export.csv"


$MemberList = get-distributiongroupmember -identity $DLName

ForEach ($Member in $MemberList){write-output "$($member.name)" | out-file -filepath "$exportfilepath" -append -noClobber}

Wednesday, 23 January 2013

Creating a Graphical User Interface (GUI) with Powershell

One of the first things I wanted to do when I started learning Powershell was to create a simple graphical user interface (GUI) that I could use to automate some of my day to day tasks. One main task in particular that took up a lot of my time was creating new user accounts. The process involved creating an Active Directory account, attaching a new mailbox to the Active directory account, adding the new account to security and distribution groups, and also sending a notification email to the new account requester with all the information in it. Doing this process manually was incredibly time consuming, and I knew there had to be a better way.

By using Powershell, I created a script that prompts with several input boxes and list boxes where I can enter all the required details to create a user account. All these inputs are saved as variables, and can then be used to run a single command to perform all the necessary steps.

Here is a screenshot of one of the input boxes that is presented during the script:


By repeating this prompt for first name, last name, office, department, title, phone number, password etc, I was able to quickly and easily collect all the information I needed to create an Active Directory account using the dsadd command - which also runs as part of the script once all the information has been collected.

Once I had an Active Directory account created, I was then able to create a mailbox and attach it to the Active Directory account using the Enable-Mailbox cmdlet.

And finally, once the Active Directory account and mailbox were created,  I could add the user to any required security/distribution groups, and send all the new account information via email to the requester. (I will cover each these topics in more detail in future blog posts.)

One of the most valuable things you can teach yourself with Powershell is how to create input boxes and list boxes for the collecting of information you require to run a command. Some examples of such commands are creating user accounts (as I just discussed), enabling or disabling ActiveSync on a mailbox, or enabling/disabling email forwarding. The possibilities are endless, though most of mine focus around the Active Directory/Microsoft Exchange technologies.

This Technet Article is what I used to get started on input boxes and highly recommend it as a starting point as the article breaks down each line of code and explains what it does.

Once you learn how to create, modify and use input boxes, you can apply the same lines of code over and over again within all your scripts - invest the time to learn it and it will save you time in the end, and open up enormous possibilities/options for your Powershell scripting.

Monday, 21 January 2013

Working with Forms Outside of Powershell ISE

Another issue I encountered when I was first starting out with Powershell scripting was a strange error that occurred when I loaded any of my scripts that used forms. (Forms are used to provide a graphical user interface (GUI) for the script - eg. input boxes, list boxes, pop up messages etc). The issue only occurred when I ran the script outside of the Powershell editor - Powershell ISE.

The following error would occur when the script started;

New-Object : Cannot find type [System.Windows.Forms.Form]: make sure the assembly containing this type is loaded

This error would occur hundreds of times, once for every line of code that referred to System forms that were being used.

After a little investigating, I discovered that you must load the .NET Framework classes being used at the beginning of the script. This is easily accomplished with the following lines of code;


[void]  [System.Reflection.Assembly]::LoadWithPartialName("System.Windows.Forms")
[void]  [System.Reflection.Assembly]::LoadWithPartialName("system.net.mail")

This will load all the system form assembly's required to use custom windows forms in your script.

Note: The [void] text simply prevents any informational messages from being displayed on the screen when the classes are loaded.

Friday, 18 January 2013

Powershell Execution Policies - Execution of Scripts is Disabled on this System

If you are attempting to run a powershell script file (.ps1) on a system for the first time, you will most likely encounter an error message similar to this;

File filename.ps1 cannot be loaded because the execution of scripts is disabled on this system.

This is related to what is known as the "execution policy" that is set for the particular user/computer you are attempting to run the scripts on.

You can view what the current execution policy is on your machine by opening a Windows Powershell prompt and running the command get-executionpolicy. There are four (4) different execution policies available:

  • Restricted - No scripts can be run. Windows PowerShell can be used only in interactive mode.
  • AllSigned - Only scripts signed by a trusted publisher can be run.
  • RemoteSigned - Downloaded scripts must be signed by a trusted publisher before they can be run.
  • Unrestricted - No restrictions; all Windows PowerShell scripts can be run.

You can modify what the current execution policy is by running the command set-executionpolicy setting where setting is one of the four (4) values specified above.

The following technet article contains further information on signing of scripts with Windows Powershell

http://technet.microsoft.com/en-us/library/ee176949.aspx