Category Archives: Powershell

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

Advertisements

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

Dynamic internet IP addresses and powershell

My lovely ISP won’t offer static IP addresses, and seems intent on changing my home IP as often as possible. This is a bit of a pain, but rather than sign-up to dyn-dns or similar, I wrote a script that I can run on a schedule at home, and then dump a file to dropbox. That way, wherever I am I can find my home IP (well, as recently as the scheduled task ran).

Param([string]$ipfile="dropbox\ipaddress.txt")
$path = "http://whatismyipaddress.com"

#open page
$ie = New-Object -ComObject InternetExplorer.Application
	$ie.Navigate("$path")
	While ($ie.Busy) { Start-Sleep -Milliseconds 200 }
	#Read contents
	$ie.Document.body.innerhtml | Out-File "$env:userprofile\my documents\http.txt"

    $pagecontent = (((get-content "$env:userprofile\my documents\http.txt" `
				| where {$_ -like "*/ip/*"}).Split("="))[$pagecontent.count-3])
    $pagecontent2 = $pagecontent.split(" ")
    $ipadd = $pagecontent2[$pagecontent2.count-2].TrimEnd('"')
    
    
    $ipadd | out-file $ipfile 

If I schedule it to check every four hours or so, I can be fairly confident of always knowing my home IP address.

2 Comments

Filed under 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