Category Archives: Microsoft

Installing Starwind VSAN on VMware

Starwind have a vSAN product which allows you to get some of the benefits of a SAN (such as HA, DRS, etc) without the expense. There is no free lunch, it does this using sync’ed local disk, but it well worth a look. It also free for small installations (two server, up to 130GB).

To test this, I have a physical host with two networks configured, “InternalNetwork”, a VMPG with no NICs assigned, and “ExternalNetwork” which does have a NIC assigned to allow outbound communication where required. On this are nested two ESX hosts, with 32GB RAM, 2 vCPU’s, and four NICs each.

You also need to download a licence for Starwind (a licensekey.swk files) and the Starwind software. Upon registered, you will be sent an email containing the details.

You will also need a couple of ESXi hosts obviously and a vCenter and Domain Controller.

Boot from the ESXi image, VMware-VIMSetup-all-5.5.0-1750795-20140201-update01.iso and perform an install, configure a partition, select password, etc. Reboot when finished.

When the hosts come up, configure an IP address for each one. I am going to use 10.10.10.10/24 and 10.10.10.11/24.

Connect them to a Virtual Center instance (installation not covered here, but it could be a virtual appliance, or installation on a Windows physical server or VM). I use a VM on the “internalNetwork” (10.10.10/24) that the hosts are on.

Add a datacenter and create a cluster, and put the two hosts in the cluster.

Once the hosts have been added, you need to create a couple of VM’s, one on each host, and each one with a couple of NICs assigned, which will host the virtual SAN. These should be Windows Server 2012. Each VM should have a second disk configured which will be used to provide the VSAN services (which will then be re-shared to ESXi). So my first SAN VM is on VMFS-1 which has ~400GB free, so I will add a disk to the VM to use that.

Really, you might get better performance also adding this to a second virtual SCSI adapter, but we can do that later.

Then install the OS on each VM, and then Vmtools.

On each of your virtual SAN’s, by running diskmgmt.msc, you should then have an unknown disk of 400GB, which is the one we created on the VMFS volume earlier.

Bring the disk online, initialise it with a GPT table, and create a partition.

Each of your virtual SANs will then need to be configured with a computer name and IP address (.15 and .16 in my case for the first adapter in each VM, and 192.168.0.15 and 192.168.0.16) for the second, although the second could be on a completely different network depending on your topology).

This is probably a good time to join each server to your domain.

On each run the Starwind-v8.exe file to do the install accepting the default (unless you don’t want the management console for instance), until you get prompted for the key. At that point choose the key and follow the rest of the install (choosing not to configure the SMI-S agent).

When finished, launch the admin console, and choose “yes” to set the default location to your newly created empty drive (e:) in my case.

From there, you need to select “Add Device” (probably best not to use the “advanced” version at this point, and give it a size. I am going to make mine 128GB, and call it SAN1-1. If you go to E:, you will also see the disk image files that you just created.

At that point, you can then configure replication between the two. This is replicating SAN1-1 to SAN2.

Drill down to the imagefile, and choose “replication manager”. Choose synchronous replication and enter the address of the other vSAN. Note that if you made your SAN diskimages much bigger than 128GB, you migt hit a licence limit… When you get the “Network Options for Replication” option, you need to select “Change Network Settings” and choose your adapters for heatbeat and sync.

When the wizard has finished, you will get confirmation:

At that point, the initial synchronization will take place, and you can connect the newly replicated volume to your ESXi hosts.

To connect to the hosts, go back to your vSphere client, and for each host, add the software iSCSI adapter (from Configuraton>Storage Adapters).

Edit the properties of your iSCSI adapter and point it to the SAN VM on that host (as each host has vSAN VM installed locally).

We haven’t actually configured any security here, but StarWind supports CHAP, as does ESXi.

Once both hosts are seeing the vSAN with a STARWIND iSCSI Disk visible, you can go to configuration>Storage, click “add storage” and create a new volume.

You should see any local unused device (perhaps the boot device) and your new STARWIND iSCSI disk. Select that partition, format it, and give it a datastore name.

You now have a VMFS volume were you can place a VM, and take advantage of HA, DRS, etc!

Leave a comment

Filed under Microsoft, VMware

Creating a clone from a snapshot on Vmware vSphere

There are times when you need something from a snapshot of a VM, but might not want to rollback to the snapshot to get it. This could be because the VM is in production and you cannot interrupt it, or you are extremely risk averse, or various other reasons.

The work around, is to create a clone of the snapshot. This will allow the existing VM to run uninterrupted, while a new clone is created.

I use the following Powershell/PowerCLI code to do that, and then disable the virtual NIC. After all, you don’t want the clone VM coming up with the same name and IP as your production VM, that would defeat the purpose of doing the clone in the first place. Just note that it doesn’t really have any troubleshooting or error catching.

$vmname = "myserver"
$VMCluster = "Production Cluster"
$VMResourcePool = "Pre-Production"
$VMdatastore = "VMFS-DATA-1"
$SnapshotNum = 0

$vm = get-vm -name $vmname | get-view
$clonename = "Clone_" + $vm.name
$clonefolder = $vm.parent

$cloneSpec = new-object Vmware.Vim.VirtualMachineCloneSpec

$cloneSpec.Location = new-object Vmware.Vim.VirtualmachinerelocateSpec
$CloneSpec.Location.Pool = (get-cluster $VMCluster | get-resourcepool $VMResourcePool | get-view).MoRef
$CloneSpec.Location.Host = (get-vm -name $vmname | get-vmhost | get-view).MoRef
$CloneSpec.Location.Datastore = (get-datastore -name $VMdatastore | get-view).MoRef
$cloneSpec.Snapshot = $vm.Snapshot.RootSnapshotList[$SnapshotNum].snapshot

$cloneSpec.Location.DiskMoveType = [Vmware.Vim.VirtualMachineRelocateDiskMoveOptions]::moveAllDiskBackingsAndDisallowSharing

write-host ("Creating clone - " + $clonename)
$vm.CloneVM_Task($cloneFolder, $cloneName, $cloneSpec)
Do {
$task = (get-task | where {$_.Name -eq "CloneVM_Task" -and $_.State -eq "Running"})
If ($task -ne $null) {Write-host ("Waiting for clone to complete - " + $task.percentcomplete[0] +"%")}
Start-sleep -s 5
}
While ($task -ne $null)
$VMadapter = get-vm -name $Clonename | get-networkadapter | set-networkadapter -startconnected:$false -confirm:$false
Write-host $VMadapter + "disabled."

Most of the information for putting this together was taken from here:
http://www.vmdev.info/?p=202

Leave a comment

Filed under Microsoft, Powershell, VMware

DirectAccess

DirectAccess has been around a while, but there seem to be a few misconceptions about it, maybe because it is much better and simpler now. On Server 2012 with Windows 8, it is awesome.

It basically allows your devices to be connected to your corporate network wherever they have internet access, without the hassle and requirement for a VPN.

So the problem of users having laptops, taking them home, and you never seeing them again is no longer a problem.

But you need IPv6 right? Only on the client, the laptop. But you need DA installed on an edge server? Nope, you can put it behind your firewall, in your DMZ. You need PKI? Nope, although obviously you should in a corporate live environment.

So what do you need? The simplest solution is a Windows 2012 server to host the role, a domain, and a Windows 8 Enterprise client. Windows 7 Enterprise is also supported, but it is more of a hassle to setup (and you need proper certificates (not self-signed).

Steps to install:

  1. Configure your external router/firewall. Basically, you need to forward HTTPS (TCP443) to the internal IP address of your DA server.
  2. On your server which will provide the DirectAccess services (in my case, a VM with a single NIC), open SerOOnver Manager and go to “Add Roles and Features”.
  3. Press “next” until you get to the point where you can actually select the roles to add. Click “Remote Access”…..
  4. Open a Powershell window and run “add-windowsfeature remoteaccess -includeManagementTools -restart”
  5. Wait for the server to finish the install and then it will restart if required (or you can leave that out and restart it manually).
  6. Then from the Start Screen, run “Remote Access Management”
  7. .Image
  8. Once this opens, you need to go to “Configuration” if it isn’t on there already.Image
  9. Then it is a matter of following the four steps, one after the other. So click “Edit” for step one.
  10. Choose “Deploy full DirectAccess for client acess and remote management” (unless you don’t want your users to be able to connect back to your network) and press “Next”.
  11. Choose a pre-created group of computers, that you will give access to this functionality, or be lazy and leave it as domain computers if you wish.
  12. Here, you want to enter an email address for the helpdesk (otherwise you can’t generate/collect client logs later), and of course you need a connection name.Image
  13. Then press finish, and “Edit” step two.
  14. Here, the wizard will try and detect whether you are an edge server, or behind a DMZ, and how many NIC’s you have. You also need to configure a method for clients to connect back to your site (and send data over HTTPS). So if you have a static IP, you can use that, or you can use a DNS name if you have one (there are several free ones around).Image
  15. At the next screen, you can select to use self-signed certificates, or not.
  16. Then you need to configure the client authentication, computer certificates, and options around Windows 7. If you want you users to connect automatically and seamlessly, active/directory credentials will be the one to choose. Maybe worth checking with your internal security over that though!Image
  17. Then click “finish”, and “Edit” step three.
  18. Here you will specify the location of the Network Locator Server. It doesn’t need to be installed on the same server, and there may be reasons to have it installed on a separate server for high-availability as the note says.Image
  19. Next you will be given the DNS configuration. How much (if anything) you need to change here will depend on your setup. For a simple installation with one domain, you probably won’t need to change anything though.Image
  20. Next you can add any additional DNS suffixes that will used, and press Next.
  21. Finally, you can enter the names of any machines that will be used to manage those clients connected via DirectAccess. This could be WSUS or SCCM servers.Image
  22. Click “finish”, and then “Edit” on step four.
  23. Here, if you are just playing with this on a test environment, you won’t be required to change anything, but otherwise you might want to extend the authentication to additional servers for end-to-end authentication/encryption. You will need IPv6 running internally to do this though.
  24. And once all that is done, press “Finish” at the bottom to do the configuration. You will be given a chance to review and make any changes before pressing the “apply” button.
  25. Once you have given it a bit of time, and all the components are green, you are ready to configure the Windows 8 client. To do this, just run “gpupdate /force” (or force it remotely from gpmc.msc).

Then on the laptop, if you look at connections, you will see a new connection, with the name you defined back in Step one. At that, point, take your laptop somewhere remote (a friends wifi connection for example), and connect to it. Once you are on the Internet, you should see a connection to your newly configured DirectAccess connection.

networks

You can test it by running a few pings, connecting to some shares, etc.

 pings

Note that the IPv4 address of the remote system is encapsulated in the IPv6 address (after the colon).

All done! Connectivity to your network (and back) whenever and wherever you are connected to the Internet!

1 Comment

Filed under Microsoft, Powershell

Rename AD users with Powershell

We need to change the name of our users in Active Directory. Not just the displayname, but also the distinguishedname. The following script will show you how to do that:

#Rebrand-Users.ps1

#Variables - edit as required
################################################################
$Sitecode = "HQ"
$container = "OU=ImportedUsers,DC=GREGDOM,DC=INT"
$server = "gregdom.int"
$company = "MyCompany"
################################################################

#Read users into variable.
$users = get-aduser -filter * -SearchBase $container
 
#Process users.
Foreach ($user in $users) {
    $newDN = $user.surname + ", " + $user.GivenName + " ($sitecode)"
	#Change display name, and company name
	set-aduser $user -Displayname $newDN -company $company -server $server -ErrorAction SilentlyContinue
	#Change distinguished name
		Try {
    		Rename-ADObject -identity $user -Newname $newDN -server $server 
		}
		Catch {
			Write-Host "$user may already exist."
		}
    }

Note that it is basically a two step process, once to change the display name, and then again to change the distinguished name, which cannot be done with set-aduser.

Leave a comment

Filed under Microsoft, Powershell

Modifying data folder permissions with Powershell

If you are doing a migration from one domain to another, you may need to change groups (old groups for new groups!). We did trying playing around with SID History, but with limited success.

With this script, you need to give it a CSV file containing a list of the groups that you want swapped (two columns, oldgroup & newgroup, in a file called groups.csv), and you will also need to edit the variables for in the script for your domain names.

There is a $removeoldgroup variable. If this is set to true, the old group is replaced. If it set to false, it is left. The script also checks to see if a particaular ACL entry is inherited. This is important because otherwise, you can get duplicate entries on the ACL (although no necessarily visible from the GUI, or having any effect in normal user use, it isn’t very clean).

Finally, as we had several areas where “Administrators” had been removed, the script will also add them back in if they are missing.

There are three files that are created by the script.
“Before Permission Changes.txt” – This will contain a list of folders and ACL’s before any processing is done.
“After Permission Changes.txt” – This will contain a list of folders and ACL’s once the processing is complete.
“folders done.txt” – This will contain a list of all folders that have been modified, as well as the date/time.

A few things to note.
1) It will fail to handle long paths (260 or more characters). You will need to create a share further down the tree in order to successfully process those. I looked at other ways around this, but didn’t find one which appealed.
2) I ran this from my Windows7 workstation against the server using UNC paths. I did test this on the server itself (Windows Server 2008, not R2), and it didn’t work as I expected with the subfolders. I don’t know if this is to do with an older version of Powershell, or an older version of .NET…
2) Test, test, test. I spent the best part of a week testing this in different scenarios, including reversing things to put the old groups back. Still, we have 140,000 folders and and problems would be a potential nightmare to solve. If you have more folders, do more testing 🙂

$destinationpath = "\\server1\share1"
$oldDomain = "EMEA"
$newDomain = "IPRUK"

$removeoldgroup = $false

"Job started at " + (Get-Date) `
	| Out-File "folders Done.txt" -Append
	
#Build a list of folders
$folders = Get-childitem $destinationpath -recurse `
	| where {$_.mode -like "d----"} 

#Get the ACL's and store in a txt file for future review.
$folders | Get-Acl `
	| Format-List @{l='Directory';e={($_.PSpath).substring(38)}},`
			accessToString `
			| Out-File -FilePath "Before permission changes.txt"

#Read the groups from a CSV with two columns, oldgroup & newgroup.
$groups = import-csv groups.csv

foreach ($folder in $folders){
	
	$aclaccess = Get-Acl $folder.FullName | select Access -ExpandProperty Access

	Foreach ($group in $groups) {
		$oldgroup = $olddomain + "\" + $group.oldgroup
		$newgroup = $newdomain + "\" + $group.newgroup

		Foreach ($accessright in $aclaccess) {
			[string]$aclIdentity = $accessright.IdentityReference
			If ($oldgroup -eq $aclIdentity) {
				
				#We don't need to change if it is inherited
				If (!$accessright.IsInherited) {
					#We have a match, so grab the full ACL from folder.
					$acl = Get-Acl $folder.fullname
					
					#Build new access rule to add to ACL.
					$FileSystemRights = $accessright.FileSystemRights
					$InheritanceFlags = $accessright.InheritanceFlags
					$PropogationFlags = $accessright.PropagationFlags
					$ACEtype = $accessright.AccessControlType
					$permission = ($newgroup, `
						$Filesystemrights, `
						$InheritanceFlags, `
						$PropogationFlags, `
						$ACEtype)
					$Rule = New-Object `
						System.Security.AccessControl.FileSystemAccessRule $permission
						Try {
							$acl.AddAccessRule($rule)
							}
						Catch {
						$FolderFullName = $folder.FullName
						$Datenow = (Get-Date)
						"$Datenow - $folderfullname, $permission : " + `
							$_ | Out-File "Group Errors.txt" -Append
							}
					#Build rule to remove from ACL.
					If ($removeoldgroup){
						$permission = ($oldgroup, `
							$Filesystemrights, `
							$InheritanceFlags, `
							$PropogationFlags, `
							$ACEtype)
						$Rule = New-Object `
							System.Security.AccessControl.FileSystemAccessRule $permission
						$acl.RemoveAccessRuleAll($Rule)
						}
					
					#Apply new access rule to folder.
					Set-Acl $folder.FullName $acl
					
					#Check for builtin\administrators, add if missing
					$adminright = $acl.access `
						| Where {$_.IdentityReference -eq "BUILTIN\Administrators"}
					If (!$adminright){
						#Build new access rule to add to ACL.
						$FileSystemRights = "FullControl"
						$InheritanceFlags = "ContainerInherit,ObjectInherit"
						$PropogationFlags = "None"
						$ACEtype = "Allow"
						$permission = ("BUILTIN\Administrators", `
							$Filesystemrights, `
							$InheritanceFlags, `
							$PropogationFlags, `
							$ACEtype)
						$Rule = New-Object `
							System.Security.AccessControl.FileSystemAccessRule $permission
						$acl.AddAccessRule($rule)	
						#Apply new access rule to folder.
						Set-Acl $folder.FullName $acl
						}
					}
				}		
			}
		}
	$FolderFullName = $folder.FullName
	"$folderFullName completed at " + (Get-Date) `
		| Out-File "folders Done.txt" -Append
	}
#Final report on permissions.
$folders | Get-Acl `
	| Format-List @{l='Directory';e={($_.PSpath).substring(38)}},`
			accessToString `
			| Out-File -FilePath "After permission changes.txt"
			
"Job completed at " + (Get-Date) `
	| Out-File "folders Done.txt" -Append

So, this, combined with Finding Long Paths, and the script for modifying USER permissions, means that I have the scripts I wanted to proceed with our domain migration!

Leave a comment

Filed under Microsoft, Powershell, Windows 2008

Finding long paths with Powershell

If you are working with “get-childitem”, it won’t deal with long paths.

Expect to see the following:

Get-ChildItem : The specified path, file name, or both are too long. The fully qualified file name must be less than 260 chara
cters, and the directory name must be less than 248 characters.

At C:\Dropbox\Powershell\Scripts\get-longpaths.ps1:7 char:26
+ $folders = Get-childitem <<<< $destinationpath -recurse `
+ CategoryInfo : ReadError: (\\server\d$…akistan Branch):String) [Get-ChildItem], PathTooLongException
+ FullyQualifiedErrorId : DirIOError,Microsoft.PowerShell.Commands.GetChildItemCommand

To deal with this, you probably want to get a list of problem folders (obviously you can only get the level where the problem first occurs, not a list of all the items in the problem folder). You can do this using a try{} catch{} structure.

The following code will build a list of folders using get-childitem (which will return pathtoolongexpection errors), but then pass that list to a foreach, which will go through each folder in turn running a get-childitem. This however is in a try{} catch{} structure so the failure will be captured, and the the foreach will move on to the next folder.

Why two runs with get-childitem? Because if we tried using a trap{} on the first one, the script would stop before continuing so we would only get the first long path.

$destinationpath = "\\server\d$\GROUPDATATEST"

Write-Host "Start check"
	
#Build a list of folders
$folders = Get-childitem $destinationpath -recurse `
	| where {$_.mode -like "d----"} 
	
Foreach ($folder in $folders){
	Try{
		$dump = Get-ChildItem $folder.FullName -ErrorAction Stop
		}
	Catch{
	$FolderFullName = $folder.fullname
		Add-Content -Value "$folderFullname" -Path "LongPaths.txt"
		}
}
	
Write-Host "Check Done"

3 Comments

Filed under Microsoft, Powershell

Using Powershell to change USER home drive permissions

There may be times, say during migration to a new domain where you need to add permissions for users in the new domain. I used the following script, run from my Windows 7 PC using Powershell 3.0, to make the changes.

It uses a csv file with two columns, “olduser”, and “newuser”. Obviously each line has the old user ID and then new one. The script will go through each user in the file, find the folder that has the same name as the user, prompt if it can’t find it, and then add permissions on the folder for the “newuser”.

It will leave the old permissions in place, because you could be doing this during the pilot phase of the process.

Here is the code.


$folderroot = Read-Host "What is the path to USER$"
$csvfile = Read-Host "What is the path to the csvfile"

#Read contents of CSV file.
$users = Import-Csv $csvfile

If ($users) {
	Foreach ($user in $users) {
		#Read line from file, and create expected path to home drive.
		$newID = $user.newuser
		$oldID = $user.olduser
		$folderpath = $folderroot + "\" + $user.olduser
		#Get the ACL for the folder.
		$acl = Get-Acl $folderpath
		#Check that the ACL isn't empty because the expect folder doesn't exist.
		if ($acl -eq $null){
			$altpath = (Read-Host "Folder not found, please enter the folder name manually for $oldID")
			if ($altpath) {
				$folderpath = ($folderroot + "\" + $altpath)
				$acl = Get-Acl $folderpath
				}
			else {
				Write-Host "Sorry, still not found."
				}
			}
		#Build a permission to add to the ACL.	
		$permission = “IPRUK\$newID”,”Modify”,”ContainerInherit,ObjectInherit”,”None”,”Allow”
		$accessrule = New-Object System.Security.AccessControl.FileSystemAccessRule $permission
		$acl.SetAccessRule($accessrule)
		$acl | set-acl -path $folderpath
		$timenow = get-date
		Write-Host "Permissions set for $oldID at $timenow"
		$users2 = $users | where {$_.olduser -ne $oldID}
		$users = $users2
		If ($users){
			$users | Export-Csv users.csv -NoTypeInformation
			}
		}
	}


Obviously, you need to be VERY CAREFUL about running this, as it would be a mess to clean up, and this code as it stands, is not production ready. It could really do with a bit more checking built in. It worked for me though 🙂

2 Comments

Filed under Microsoft, Powershell, Windows 2008