Archive for the ‘IT’ Category

Extract ProxyAddresses to a CSV file

Tuesday, May 10th, 2016

The code snippet below will allow you to extract a users proxy addresses, one per line, to a CSV fie ready to import into a foreign exchange system.


$recordset = get-mailbox -resultsize unlimited | select samaccountname, displayname, emailaddresses

$result = @()

foreach ($record in $recordset) {

foreach ($address in $record.emailaddresses) {

$add = $record.samaccountname + “,” + $record.displayname + “,” + $address.proxyaddressstring

$result += $add



$result | out-file c:\support\alladdresses.txt



When importing into the other system, you may want to convert SMTP (uppercase) to smtp (lowercase) and similar for X400, X500 and SIP addresses or ad .tolower() to $address.proxyaddressstring when extracting the addresses above.


Getting the cluster size of CSV disks in Hyper-V

Saturday, April 23rd, 2016

If you want to check the cluster size of NTFS formatted disks used for Cluster Shared Volumes, here’s some handy code below. Just change the names of the hyper-v clusters you want to check in red and run from an administrative level powershell prompt.

If you want another row of information from the fsutil command, just change the number where it says $arr[9]

Import-Module FailoverClusters


#Get CSVs foreach cluster

foreach($Cluster in $Clusters){

      $c = Get-ClusterSharedVolume -Cluster $Cluster 

     $csvs += $c


foreach ($csv in $csvs) {

     invoke-command -ComputerName $csv.ownernode -scriptblock {

                 param ($name,$node)

                 $Clustersize = fsutil fsinfo ntfsinfo “C:\ClusterStorage\$name” 

                $arr = $Clustersize -split ‘`n’

                write-host $name ” on ” $node ” has ” $arr[9]    

         }   -argumentlist $, $csv.OwnerNode



The output reports against the owner node for the CSV. As the underlying disk for the CSV is the same on all nodes, I report against the owner node to limit the output to one row per CSV.

Powershell launch options

Tuesday, December 29th, 2015

There are a few things that we can do when launching powershell.

1) We can simply start qowrdshell by typing “powershell” at the command prompt.
2) We can launch powershell faster by not displaying the banner – we do this using the command “powershell -nologo”
3) We can launch an older version of powershell by stating which version to launch e.g. “powershell -version 3”
4) We cab launch powershell using a specific configuration fie (e.g. “powershell -psconsolefile my console.psc1”
5) we can launch powrrshell an tell it to run a command on launch – powershell -command “& {get-service}”

Common PowerShell commands for Hyper-V

Sunday, November 9th, 2014

This blog post will list some simple things you can do with PowerShell to make Hyper-V easier to manage – the details and commands for this post are taken from TechEd Australia 2014 – you can watch the original session at

Want to find a command to use ?

e.g. Get-Command –Module Hyper-V –Name *vhd*

Swap the text in RED for the type of command you want to look for. If you are not sure if it’s a Hyper-V command then don’t limit it to a module bur search all loaded modules.

Get-command *Adapter*

If you want to list all of the available commands in a module you need to know the module name.

Get-Command –Module Hyper-V

If you are using Get-Help to understand how to use individual commands, use

Get-Help Update-Help

to understand how to update the help files to the latest versions of the help files

If you just want to see how to construct an individual command type


This will pop up a screen showng all the available commands. You can the search for a command and the GUI will allow you to browse the options for that command.

Creating new VMs is a cinch – enter a command similar to the below:

 New-VM –Name “VM Name” –MemoryStartupBytes 512MB –Path “C:\CulesterVolumes\Volume1\MyVMs

If you want to create 10 new VMs then this can be done with a single command line by creating an array holding 10 values and then ForEach of those items in the array, create a new VM. An example of the code required is:

$CreateVM = @(): (1..10) | %{ $CreateVM += new-VM –Name “MyVM$_”}

This will create 10 new virtual machines named MyVM1, MyVM2 tjhrough to MyVM10.

Want to know which virtual machines are powered down ?

Get-VM | where-object {$_.state = ‘Off’}

The above is for PowerShell 3 – in PowerShell 4 it’s been made even easier !

Get-VM | Where-Object State –eq Off

As you can see, we no longer need to tell PowerShell that state is an attribute if our object, it understands the context. It also doesn’t need to be told that “off” is a value rather than a variable, it just works it out – amazing !

If you want to be able to review the results in something other than the PowerShell command line interface, just pipe the results to “Out-Gridview” to open them in a grid in a new interface

Get-VM | Out-GridView

This is very useful in very large environments as it allows searching of the results.

Want to create a new disk ?

New-VHD C:\CustomerVolumes\Volume1\MyVHD\MyDisk.VHD –SizeBytes 60GB

This will create a new 60GB disk. If you want a dynamic disk, add the –Dynamic switch.

Want to convert a VHD to the newer VHDx format (to expand the disk beyond 2TB) ?

Convert-VHD C:\CustomerVolumes\Volume1\MyVHD\MyDisk.VHD C:\CustomerVolumes\Volume1\MyVHD\MyDisk.VHDX -Passthru

The –Passthru switch ensures that the results of the command are disaplyed on the screen (it says to pass through the output to the pipeline, as no commands follow it simply writes to the screen) – without this the command simply executes. Don’t forget, you can use a command line to get all VM, get all of their disks and convert all disks to the new format.

If you want to connect the disk you created to a virtual machine then simply

Add-VMHardDiskDrive –VMName MyVM –Path C:\CustomerVolumes\Volume1\MyVHD\MyDisk.VHDX -Passthru

Want to move all of your VMs from cluster to another ? Well, you can do live motion or a shred noting move but to do this using PowerShell we can simply export and import.

Get-VM | Export-VM –Path C:\MyExportedVMs –Passthru

Now that we can create disks and VMs, we can also create networking within Hyper-V also. To create a new virtual switch we can simply

New-VMSwaitch “MyvSwitch” –SwitchType Internal

This will create a new vSwitch to enable communications only within the node itself – To create a switch available for external use we can use the command

New-VMSwitch “QoS Switch” -NetAdapterName “Wired Ethernet Connection 3” -MinimumBandwidthMode Weight

i.e. External is assumed by default – the above switch will be enabled for QoS for traffic which is especially useful where NICs have been presented to the Management OS also.

If we want to add a network adapter to our virtual machine we use a command similar to the below

Add-VMNetworkAdapter –VMName “MyVM” –Name “NewNIC” –Passthru

If we want to present a NIC to the ManagementOS (for converged networking) then, instead of using the –VMName switch, we use the –ManagementOS switch)

Add-VMNetworkAdapter –ManagementOS –Name “NewNIC” –SwitchName “MyvSwitch” –Passthru

As you can see, we connect to the switch at the time. For our “standard” VM NICs, we can connect the network adapter we created to our vSwitch as follows

Connect-VMNetworkAdapter –VMName “MyVM” –SwitchName “MyvSwitch

Once our VM is created we can migrate it between nodes

Move-VM –Name MyVM -DestinationHost Server2

If we don’t have a cluster and want to perform a “shared nothing” migration between stand alone nodes or even between clusters then we can do this

Move-VM MyVM Server2 –IncludeStorage –DestinationStoragePath C:\ClusterVolumes\Volume2\MyVM

Of course, we can use tokens to move multiple machines one after the other.

Get-VM –Name * | % {Move-VMStorage $_.Name “C:\ClusterStorage\Volume2\$($_.Name)” }

The above will move the storage only for all of our virtual machines to a new disk – great for rebalancing our storage.

We can set QoS for our virtual machines – this is only bandwidth based and does not priorities traffic by type.

Set-VMNetworkAdapter –VMName MyVM –Name MyNIC –MaximumBandwidth 100MB –MinimumBandwidthAbsolute 20MB –Passthru

We can also set Access Control Lists on our VM (essentially at the virtual switch level rather than in the OS) using PowerShell. We do this to ensure that our environment is safe. For example, this should be done to prevent access to the management layer from tenant VMs.

Add-VMNetworkAdapterACL –VMName myVM –RemoteIPAddress –Direction Outbound –Action Deny

As you can see, the ACL is not fully featured and is based on IP address though it can be filtered by VM NIC also, it secures traffic between IP addresses and the direction (Inbound, Outbound of BOTH).

You can view any ACLs applied to a VM by using the command

Get-VMNetworkAdapterACL –VMName MyVM

We can set memory within a VM as follows

Set-VMMemory –VMName MyVM –DynamicMemoryEnabled $True – MaximumBytes 2GB –MinimumBytes 1GB –StartupBytes 2GBPasteur

Again, we can apply to multiple machines either by listing them

Set-VMMemory –VMName MyVM1, MyVM2, MyVM2

Or by tokenizing the name

Set-VMMemory –VMName MyVM*

We can also start multiple VMs in the same way

Get-VM MyVM* | Start-VM -Passthru

If we want to monitor our VMs, we can use VM Resource Metering to record what resources each VM is consuming – this can only be set via PowerShell

Get-VM | EnableVMResourceMetering

Will enable resource metering for all VMs

Get-VM –Name MyVM | Measure-VM

Will return the performance statistics for an individual VM that is being measured / metered.



PowerShell History Viewer

Friday, March 21st, 2014

Here’s a nice feature of the Active Directory Administrative Centre – the PowerShell History Viewer. Simply undertake your daily tasks as usual and the PowerShell History Viewer will capture what you do and allow you to see the commands it used to perform those tasks. You’ve then taken the first steps needed to automate your most common tasks as you will:

  1. Know which tasks you carry out most regularly and
  2. Know the PowerShell commands to perform those tasks.

To expose the PowerShell History Viewer in the Active Directory Administrative Centre, click on the up arrow at the bottom right of the Admin Centre.


You can now perform your usual tasks and the PowerShell for those tasks will be captured there.

The PowerShell used is displayed below – checking the “Show All” box will show all PowerShell commands issued to run the Admin Centre, not just those related to you entering instructions.


For the “full” command, right click it and select “Copy”


You can then paste it into your favourite editor such as the PowerShell Integrated Scripting Engine (ISE). If you would prefer to just read the string in the GUI then clicking the + sign to the left of the command renders it readable.



Shutting down the Admin Centre will clear the history so do take a note of any commands you need first.






XenApp and XenDesktop recommended optimisations and settings

Friday, March 21st, 2014

Excellent blog post here detailing recommended optimisations to make when presenting Windows 8 or XenApp using Citrix products. Applies just as well for RDS installs.

The Windows 7 optimization guide can be found at

How to set XenDesktop Delivery Controllers to use SSL

Monday, March 17th, 2014

Good Citrix article at

Note the need to add dashes to the GUID or you get a “Parameter is incorrect” message.

Listing group membership and extracting into a CSV file for multiple groups

Friday, February 21st, 2014

I’ve been hunting around the web for a powershell script that will list the members of multiple groups and haven’t been able to write one so I’ve written my own.

This script isn’t intended to be perfect but it will give you the bare bones of how to write your script. For example, this script work on the basis of entering all or part of a group name and then reporting on that group. If you enter a blank or * from the group name then it will export user membership in all groups as direct members (add a  recursive switch if you need membership of nested groups). This is useful if you have a group naming convention as you can easily drill down into the groups you want.

It also doesn’t filter out computer accounts so it depends if that’s an issue for you and it reports against the whole AD but you can always filter the Get-ADGroup command to scope it to an individual OU or area of AD.

In any event, like I said I wasn’t able to find anything around to do this so hopefully, if you need to do this, this script will give you a good head start on exporting these values from your directory.

Here’s the script – if copying and pasting into notepad remember to correct some characters such as ‘ and “.


Import-Module ActiveDirectory
Write-Host “********************************************************”
Write-Host “* This script will dump out users in named groups, all *”
Write-host “* groups or a range of groups. You will be guided *”
Write-host “* through the process *”
Write-Host “* *”
Write-Host “* All output will be saved to C:\Support\ScriptOutput\ *”
Write-Host “********************************************************”

$strFileName = $(
$selection = read-host ‘Enter the name of file to save results to. Include an extention. (Default = Groupmembership.csv)’
if ($selection) {$selection} else {‘GroupMembership.csv’}

$strFileName = “C:\Support\ScriptOutput\” + $strFilename
If (Test-Path $strFileName){
Remove-Item $strFileName

Write-Host ‘Enter name of group you would like to export’
Write-Host ‘The script will look for matching groups’
Write-Host ‘Entering the first part of the group name will return all matching groups’
Write-Host ‘For example, Entering “LG-APP-” without the quotation marks will return all application groups’
Write-Host ‘Pressing return will list membership of ALL groups’
Write-Host ‘***** WARNING *****’
Write-Host ‘Exporting all group memberships will take some time as it will’
Write-Host ‘include all built in groups and distribution lists – use with caution’

$strGroupNames = $(
$selection = Read-Host ‘Enter name of group you would like to export (no value will return all groups)’
if ($selection) {$selection + ‘*’} else {‘*’}

Write-Host ‘Exporting teams with names like ‘ $strGroupNames ‘ to ‘ $strFilename
$data= ‘Group,UserName,UserID’
Write-Output $data | out-file -FilePath $strFileName -Append
$groups = Get-ADGroup -filter {name -like $strGroupNames}
foreach ($Group in $Groups)
$usernames = Get-ADGroupMember $($

foreach ($user in $usernames)
$data = $Null
$data = $data + $ + “,” + $ + “,” + $user.saAMAccountName
Write-Output $data | out-file -FilePath $strFileName -Append



Performing Exchange 2010 datacentre failovers

Friday, February 21st, 2014

A nice wizard driven process is available to walk you through your particular scenario here.

Install and Configure MDT 2013 (Part 5)

Saturday, January 4th, 2014

In the last part of this series we looked at creation of media for remote deployments and centralised monitoring of deployments. In this part of the series we will look at replacing media with the use of Linked Deployment Shares for remote offices.

As with Media, the contents of a Linked Deployment Share are dictated by the Selection Profile associated with the Linked Deployment Share. If the “Everything” Selection Profile is used then the linked share will be an exact replica of the central Deployment Share at the time that the Linked Deployment Share is created. That’s important to note as any changes made to the centralised Deployment Share will not be replicated to the Linked Deployment Share unless and until you force the Linked Deployment Share to be updated. The contents of the Linked Deployment Share can be updated manually (by running the update command) or more regularly by use of either DFS or a scheduled task running robocopy or a PowerShell command.

Creation of the Linked Deployment Share is relatively simplistic and is achieved by right clicking the Linked Deployment Shares node in the Advanced Configuration section of the Deployment Workbench GUI and selecting “New Linked Deployment Share”.


However, the wizard that is launched requires that the share that will be turned into a Linked Deployment Share must already exist and have been created. For the purposes of this post I have created a new share on the same server. This is what you would need to do if you were to use DFS as a replication mechanism. If a scripted replication is used then I would recommend the use of a PowerShell command (shown later in this post) or remembering to manually update the share as and when the centralised Deployment Share is modified. What you will do in your environment will in large part depend on how often the centralised Deployment Share is updated and whether you will remember to update and linked Deployment Shares. If you have several remote shares then you may want to use a series of PowerShell commands in a single script to update all remote shares at the same time.

As for the centralised share, I have created the remote share as an administrative share by appending a $ sign to the name. The share permissions are “Everyone | Full Control” in line with Microsoft Best Practice. I have removed the “Users” NTFS permissions and replaced them with Read / Execute permissions for an MDT specific account.



We can then create our Linked Deployment Share. If you have been following this series then the wizard should be familiar to you.



Note that we DON’T select the file path for our Linked Deployment Share (as by design it should be on a remote server). Instead, we enter an UNC path to the share including the $ sign as it’s a hidden share and select an appropriate Selection Profile to determine which content should be replicated to the remote share. We also select to either merge the contents or replace the contents of the existing share. It’s not immediately obvious (as we have created an empty share) but this allows you to pre-stage the content in the remote share (by using an external drive to manually transfer the data). This works in the same way as for creation of media in that the Linked Deployment Share object is created in the GUI but no data is copied into the share itself.



If we right click the Linked Deployment Share object created we can inspect its properties.




As you can see, there are no additional tabs (unlike for the Deployment Share. If you want to configure the WinPE settings for the Linked Deployment Share you need to do that through its root Deployment Share.

We can then replicate the content by right clicking the deployment share and selecting “Replicate Content”.


The replication will immediately start and the amount of time taken will depend on the amount of content you have, speed of link and hardware resources available. The boot images will be recreated for the Linked Deployment Share, specifically to ensure that the bootstrap.ini file contains the correct value for DeployRoot (the location of the Linked Deployment Share).




Once replication has been completed the summary screen present you with a “View Script” button that allows you to access the PowerShell command used to replicate the share.



Import-Module “C:\Program Files\Microsoft Deployment Toolkit\bin\MicrosoftDeploymentToolkit.psd1”

New-PSDrive -Name “DS001” -PSProvider MDTProvider -Root “D:\DeploymentShare”

Update-MDTLinkedDS -path “DS001:\Linked Deployment Shares\LINKED001” -Verbose


This script can be used to automate replication of the Linked Deployment share but this will recreate the WinPE boot disks each time also. This can be overcome by clearing the below checkbox in the Linked Deployment Share properties.



You should note that the customsettings.ini file is NOT replicated between servers with the default settings being created in the Linked Deployment Share. Using this method of replication you will then need to manually update the customsettings.ini file.



As well as either manually replicating the data as above or using a Scheduled task running the PowerShell script, you can simply set up a DFS-R share and replicate either the Linked Deployment Share (so that only a subset of data replicates) or the original Deployment Share (so that all data replicates).

If replicating the original Deployment Share some changes need to be made to the bootstrap.ini file so that, when booting, WinPE sets the DeployRoot value based in the clients default gateway. An example configuration is shown below.

Priority=DefaultGateway, Default







I think that you can see that your choices are between using the built in non-automated solution or creating your own automated solution and configuring MDT to function between sites. I would suggest that the latter, while needing more set-up (especially when you factor in deploying and configuring DFS-R) is the more functional and robust solution.

In the next post we’ll go through how to configure a database for MDT to centralise the functionality provided by the customsettings.ini file.