Powershell / Powercli script to report on VMs and their VMDKs

Here is a report I put together to quickly view all VMs their VMDKs and the Datastores those VMDKs are sitting on. This is not meant to be a report to view total storage or free space on either the VMs or their Datastores, nor are we looking for orphaned vmdk files. Although I may add those features to this report later on.

Update 3/13/2014: Script now reports on Size and how the data is presented has been improved.

Issue: Review VMDK files for any that don’t have the same name as the VM names in VCenter.

Purpose: Scan and report on VMware VM’s VMDKs and what Datastores they are tied to.

Side Notes:

  • You must have Powercli installed on the machine this report runs off of.
  • The admin account used must have enough permissions to run the given commands.
  • It is possible to have two VMs in vCenter with the same name. So in the report you may see a single server when in fact it is two separate servers.
  • If that happens you’ll see a single instance of that VM’s name with more than the expected number of disk.
#=====================================================================================================#
# Author: Robert Stacks
# Date: 7/18/2012
# Updated: 3/13/2012
# Verson: 1.1
#
# Purpose: 
# Scan and report on Datastores, and related VM's VMDK visible to vCenter
# 
# Updates:
# 3/12/2012
# - Added a column to show the current host ESXi server, Split Folder from VMDK info, and also added size
# - Fixed some spelling and updated comments
# - Fixed some flow logic and adjusted table row color, table padding, and sizing.
#=====================================================================================================#

#Add Snapins
Add-PSSnapin VMware.VimAutomation.Core

#===========================#
#User Adjustable Variables  #
#===========================#

#Vcenter Logon Info
$ESXserver = "vcenterserver.domain.com"
$ESXuser = "username"
$ESXpassword = "password"

#Mail Server Variables
$SMTPserver = "mail.domain.com"
$from = "VMwareReporter@domain.com"
$to = "sysadmins@domain.com"

#===========================#
#Main Script                #
#===========================#

#Determine if already connected to VCenter and if not connect
if ( $DefaultVIServers.Length -lt 1 )
{
  Connect-VIServer -Server $ESXserver -User $ESXuser -Password $ESXpassword -WarningAction SilentlyContinue | Out-Null
}

# Format html report
$htmlReport = @"
<style type='text/css'>
.heading {
 	color:#0B1ABF;
	font-size:14.0pt;
	font-weight:700;
	font-family:Verdana, sans-serif;
	text-align:left;
	vertical-align:middle;
	height:20.0pt;
	width:416pt;
}
.colnames {
 	color:white;
	font-size:11.0pt;
	font-weight:700;
	font-family:Tahoma, sans-serif;
	text-align:center;
	vertical-align:middle;
	border:.5pt solid windowtext;
	background:#730000;
}
.lblueback {
	color:windowtext;
	font-size:10.0pt;
	font-family:Arial;
	text-align:left;
	vertical-align:middle;
	border:.5pt solid windowtext;
	background:#B8CCE4;
}
.greyback {
	color:windowtext;
	font-size:10.0pt;
	font-family:Arial;
	text-align:left;
	vertical-align:middle;
	border:.5pt solid windowtext;
    #background:#D8D8D8;
}

</style>
<table style='border-collapse:collapse;table-layout:auto;width:auto;padding:5px'>
 <tr style='height:15.0pt'>
   <th colspan=6 height=40 width=auto class="heading">
	<center> VM Datastore Report </center></th>
 </tr>
 <tr>
  <th class="colnames">VM Name</th>
  <th class="colnames">Host</th>
  <th class="colnames">DataStore</th>
  <th class="colnames">Folder</th>
  <th class="colnames">FileName</th>
  <th class="colnames">Size/GB</th>
 </tr>
"@

#get a list of VMs
$vmlist = Get-VM -Server $ESXserver | Sort

#counter to manage alternating row color
$colorcounter = 0

#Master part of the script, loops through each VM and creates table with data
ForEach ($vm in $vmlist)
{	
  #If loop to determine color of Rows related to given VM
  if ($colorcounter%2 -eq 0)
	{
		$tablecell = @"
		<td class='lblueback'>
"@
}
  else 
	{ 
		$tablecell = @"
		<td class='greyback'>
"@
}
  
  # Grab VMDK information and the Datastores tied to them.
  $vmdisk = Get-VM $vm | Get-harddisk
  
  # Split out disks where a VM has more than a single disk, also split out the name of the Datastore
  # from the name/path of the vmdk file, then split the Folder Name from the VMDK name.
  $vmdiskDatastore=($vmdisk | %{$_.Filename.Split('[]')[1]})
  $vmdiskfilename=($vmdisk | %{$_.Filename.Split('[]')[2]})
  $vmdiskFolder=($vmdiskfilename | %{$_.Split('/')[0]})
  $vmdiskVMDK=($vmdiskfilename | %{$_.Split('/')[1]})
  $vmdisksize=($vmdisk | %{$_.CapacityKB})
  
  # determine the length of the array so we know if there was more than one hard drive for a given VM.
  $count = $vmdiskfilename.count - 1
  
  # Begin building the html report, inserting the name of the VM in the 1st Column and Host Name into the 2nd 
  $htmlReport = $htmlReport + 
  "<tr>" + $tablecell + $vm.Name + "</td>" +
  $tablecell + $vm.host.Name + "</td>"
  
  # Based on the number of hard drives in the count value the report is generated in one of two ways
  if($count -le 0)
  {
  	# There is only one hard drive so the values will not be in an array we just need to build the table row with data
  	$htmlReport = $htmlReport + 
	$tablecell + $vmdiskDatastore + "</td>" + 
    $tablecell + $vmdiskFolder + "</td>" +
	$tablecell + $vmdiskVMDK + "</td>" +
	$tablecell + $vmdisksize / 1MB + "</tr>"
  }
  else
  {
  	# There is more than one hard drive, because of table formatting we handle the 1st row different from the 2nd row.  Data is in an array.
  	$htmlReport = $htmlReport +
    $tablecell + $vmdiskDatastore[0] + "</td>" + 
    $tablecell + $vmdiskFolder[0] + "</td>" +
	$tablecell + $vmdiskVMDK[0] + "</td>" +
	$tablecell + $vmdisksize[0] / 1MB + "</tr>"
  
  # There is more than one hard drive so we will loop through the array and and place them in the report
 	$x=1
    While($x -le $count)
	{
    	$htmlReport = $htmlReport +
     	"<tr>" + $tablecell + "" + "</td>" + 
		$tablecell + "" + "</td>" +
    	$tablecell + $vmdiskDatastore[$x] + "</td>" + 
    	$tablecell + $vmdiskFolder[$x] + "</td>" +
		$tablecell + $vmdiskVMDK[$x] + "</td>" +
		$tablecell + $vmdisksize[$x] / 1MB + "</tr>"
		$x= $x+1
  	}
   }
   # value used in conjunction with Foreach and if loop to rotate color in table
   $colorcounter = $colorcounter + 1
 }
 
 # We are done gathering data from vCenter so we disconnect
 Disconnect-VIServer -Server $ESXserver -Force:$true -Confirm:$false

# Send email
$subject = "VMware VM Datastore Report"
$emailbody = $htmlReport
$mailer = New-Object Net.Mail.SMTPclient($SMTPserver)
$msg = New-Object Net.Mail.MailMessage($from, $to, $subject, $emailbody)
$msg.IsBodyHTML = $true
$mailer.send($msg)

Example of output:
datastorereportexample

Advertisements

11 Comments

Monitor VMware for SnapShots

Here is something I recently put together to monitor VMware Snapshots. 

The issue: The backup solution creates snapshots daily but if something goes wrong it doesn’t clean up a snap.

The solution: Using this simple powercli script, we monitor and check to see if any VM’s have snapshots over 1 day old. If so we highlight them in the report, other snapshots are simply in the report.

Side Note: Not sure if I’m happy with the colors I used in the report but it does grab ones attention.


#=====================================================================================================#
# Author: Robert Stacks
# URL: RandomTechMinutia.wordpress.com
# Date: 6/18/2012
# Updated: 7/2/2012
# Version: 0.4
#
# Purpose:
# Scan and report on Snapshots that are older than 1 day in VCenter
#=====================================================================================================#

#Add Snapins
Add-PSSnapin VMware.VimAutomation.Core

#Get todays Date
$date = Get-Date

#===========================#
#User Adjustable Variables  #
#===========================#

#Name of your Company for Report Title
$CompanyName="CompanyName"

#Vcenter Logon Info
$ESXserver = "vcenterserver.yourdomain.com"
$ESXuser = "vmwareuser"
$ESXpassword = "password"

#Adjust report +/- age of Snap Shots in days
$TimeinDays = 1

#Mail Server Variables
$SMTPserver = "mail.yourdomain.com"
$from = "VMwareReporter@yourdomain.com"
$to = "admin@yourdomain.com"

#===========================#
#Main Script                #
#===========================#

#Determine if already connected to VCenter and if not connect
if ( $DefaultVIServers.Length -lt 1 )
{
Connect-VIServer -Server $ESXserver -User $ESXuser -Password $ESXpassword -WarningAction SilentlyContinue | Out-Null
}

# Format html report
$htmlReport = @"
<style type='text/css'>
.heading {
color:#0B1ABF;
font-size:14.0pt;
font-weight:700;
font-family:Verdana, sans-serif;
text-align:left;
vertical-align:middle;
height:20.0pt;
width:416pt;
}
.colnames {
color:white;
font-size:10.0pt;
font-weight:700;
font-family:Tahoma, sans-serif;
text-align:center;
vertical-align:middle;
border:.5pt solid windowtext;
background:#730000;
}
.text {
color:windowtext;
font-size:10.0pt;
font-family:Arial;
text-align:center;
vertical-align:middle;
border:.5pt solid windowtext;
background:#EAEAEA;
}
.textlate {
color:#730000;
font-size:10.0pt;
font-family:Arial;
font-weight:bold;
text-align:center;
vertical-align:middle;
border:.5pt solid windowtext;
background:#FFFF00;
}
</style>
<table border=0 cellpadding=.5 cellspacing=0 width=556
style='border-collapse:collapse;table-layout:auto;width:600pt'>
<tr style='height:15.0pt'>
<th colspan=6 height=40 width=555>
<center>- $CompanyName - </center></th>
</tr>
<th colspan=6 height=40 width=555>
<center> vSphere Snapshots Daily Report </center></th>
</tr>
<tr>
<th>Name</th>
<th>Note</th>
<th>Size (MB)</th>
<th>VM</th>
<th>VM State</th>
<th>Date Created</th>
</tr>
"@

$vmlist = Get-VM -Server $ESXserver
$snapshotCount = 0

ForEach ($vm in $vmlist)
{
# List snaphosts
$snapshots = Get-Snapshot -VM (Get-VM -Name $vm.Name) -WarningAction SilentlyContinue

if ($snapshots -ne $null)
{

ForEach ($snapshot in $snapshots)
{
if( $snapshot -ne $null)
{
$snapshotCount = $snapshotCount + 1

if ($snapshot.created -lt (Get-Date).AddDays(-$TimeinDays))
{
$htmlReport = $htmlReport +
"<tr><td class='textlate'>" + $snapshot.Name + "</td>" +
"<td class='textlate'>" + "Snapshot Over 24 Hours Old" + "</td>" +
"<td class='textlate'>" + $snapshot.SizeMB + "</td>" +
"<td class='textlate'>"+ $vm.Name + "</td>" +
"<td class='textlate'>" + $vm.PowerState + "</td>" +
"<td class='textlate'>" + $snapshot.Created + "</td></tr>"
}
else
{
$htmlReport = $htmlReport +
"<tr><td class='text'>" + $snapshot.Name + "</td>" +
"<td class='text'>" + "Snapshot Less Than 24 Hours Old" + "</td>" +
"<td class='text'>" + $snapshot.SizeMB + "</td>" +
"<td class='text'>"+ $vm.Name + "</td>" +
"<td class='text'>" + $vm.PowerState + "</td>" +
"<td class='text'>" + $snapshot.Created + "</td></tr>"
}
}
}
}
}

$htmlReport = $htmlReport + "</table>"

Disconnect-VIServer -Server $ESXserver -Force:$true -Confirm:$false

# Send email
$subject = "vSphere Snapshots Daily Report: " + $snapshotCount + " snapshots"
$emailbody = "No snapshot was found."
if( $snapshotCount -gt 0 )
{
$emailbody = $htmlReport
}
$mailer = New-Object Net.Mail.SMTPclient($SMTPserver)
$msg = New-Object Net.Mail.MailMessage($from, $to, $subject, $emailbody)
$msg.IsBodyHTML = $true
$mailer.send($msg)

Here is what it will look like in a email.

,

2 Comments

Taking Ownership of a Registry Key using Powershell

A while back we setup and installed QRadar as syslog server for our IT Infrastructure.  The system works pretty well, Linux and Unix hosts send syslogs to it.  Routers and Switches and other such devices are checked via snmp.  The real challenge was to get Microsoft 2008 R2 servers working with it.

The way it works with Microsoft, is that QRadar logs into a server with Admin rights, and creates a DCOM object that then fetches logs via WMI and sends them back to the QRadar Server.  This requires a very specific set of rights including the taking ownership of two registry keys that by default have the TrustedInstaller account as the owner.  Seeing as I need to do this as I setup new servers, as part of a auto install process I wanted to script the whole thing.

The big challenge was scripting a ownership change of the registry.  I ended up having to revert to some VB to make it happen.  However it all runs as a powershell script.  So here are the highlights and that part of the script.

Problem

  • Need to grant special permissions on a Registry Key via Script
  • Need to take ownership of a Registry Key via Script

Key Points

  • You must run this script as the user that is taking ownership
  • You can’t give ownership it must be taken thus the 1st bullet
  • Make sure to take a backup of your registry before you change it or permissions

Special thank you to Tome Tanasovski on the technet forms who wrote this originally, I just added comments and figured out how to make it work with a hive key I was interested in that had a special character in it.


function enable-privilege {
 param(
 ## The privilege to adjust. This set is taken from
 ## http://msdn.microsoft.com/en-us/library/bb530716(VS.85).aspx
 [ValidateSet(
 "SeAssignPrimaryTokenPrivilege", "SeAuditPrivilege", "SeBackupPrivilege",
 "SeChangeNotifyPrivilege", "SeCreateGlobalPrivilege", "SeCreatePagefilePrivilege",
 "SeCreatePermanentPrivilege", "SeCreateSymbolicLinkPrivilege", "SeCreateTokenPrivilege",
 "SeDebugPrivilege", "SeEnableDelegationPrivilege", "SeImpersonatePrivilege", "SeIncreaseBasePriorityPrivilege",
 "SeIncreaseQuotaPrivilege", "SeIncreaseWorkingSetPrivilege", "SeLoadDriverPrivilege",
 "SeLockMemoryPrivilege", "SeMachineAccountPrivilege", "SeManageVolumePrivilege",
 "SeProfileSingleProcessPrivilege", "SeRelabelPrivilege", "SeRemoteShutdownPrivilege",
 "SeRestorePrivilege", "SeSecurityPrivilege", "SeShutdownPrivilege", "SeSyncAgentPrivilege",
 "SeSystemEnvironmentPrivilege", "SeSystemProfilePrivilege", "SeSystemtimePrivilege",
 "SeTakeOwnershipPrivilege", "SeTcbPrivilege", "SeTimeZonePrivilege", "SeTrustedCredManAccessPrivilege",
 "SeUndockPrivilege", "SeUnsolicitedInputPrivilege")]
 $Privilege,
 ## The process on which to adjust the privilege. Defaults to the current process.
 $ProcessId = $pid,
 ## Switch to disable the privilege, rather than enable it.
 [Switch] $Disable
 )

## Taken from P/Invoke.NET with minor adjustments.
 $definition = @'
 using System;
 using System.Runtime.InteropServices;

public class AdjPriv
{
[DllImport("advapi32.dll", ExactSpelling = true, SetLastError = true)]
internal static extern bool AdjustTokenPrivileges(IntPtr htok, bool disall,
ref TokPriv1Luid newst, int len, IntPtr prev, IntPtr relen);

[DllImport("advapi32.dll", ExactSpelling = true, SetLastError = true)]
internal static extern bool OpenProcessToken(IntPtr h, int acc, ref IntPtr phtok);
[DllImport("advapi32.dll", SetLastError = true)]
internal static extern bool LookupPrivilegeValue(string host, string name, ref long pluid);
[StructLayout(LayoutKind.Sequential, Pack = 1)]
internal struct TokPriv1Luid
{
public int Count;
public long Luid;
public int Attr;
}

internal const int SE_PRIVILEGE_ENABLED = 0x00000002;
internal const int SE_PRIVILEGE_DISABLED = 0x00000000;
internal const int TOKEN_QUERY = 0x00000008;
internal const int TOKEN_ADJUST_PRIVILEGES = 0x00000020;
public static bool EnablePrivilege(long processHandle, string privilege, bool disable)
{
bool retVal;
TokPriv1Luid tp;
IntPtr hproc = new IntPtr(processHandle);
IntPtr htok = IntPtr.Zero;
retVal = OpenProcessToken(hproc, TOKEN_ADJUST_PRIVILEGES | TOKEN_QUERY, ref htok);
tp.Count = 1;
tp.Luid = 0;
if(disable)
{
tp.Attr = SE_PRIVILEGE_DISABLED;
}
else
{
tp.Attr = SE_PRIVILEGE_ENABLED;
}
retVal = LookupPrivilegeValue(null, privilege, ref tp.Luid);
retVal = AdjustTokenPrivileges(htok, false, ref tp, 0, IntPtr.Zero, IntPtr.Zero);
return retVal;
}
}
'@

$processHandle = (Get-Process -id $ProcessId).Handle
$type = Add-Type $definition -PassThru
$type[0]::EnablePrivilege($processHandle, $Privilege, $Disable)
}

enable-privilege SeTakeOwnershipPrivilege
#This is the Key to take ownership of, I left this in here as an example.  Note I had to change "ChangePermission" to "Take Ownership"
$key = [Microsoft.Win32.Registry]::ClassesRoot.OpenSubKey('CLSID\{76A64158-CB41-11D1-8B02-00600806D9B6}',[Microsoft.Win32.RegistryKeyPermissionCheck]::ReadWriteSubTree,[System.Security.AccessControl.RegistryRights]::TakeOwnership)

#You must get a blank acl for the key b/c you do not currently have access
$acl = $key.GetAccessControl([System.Security.AccessControl.AccessControlSections]::None)

#domain\user is the user that is going to take ownership
$me = [System.Security.Principal.NTAccount]"domain\user"
$acl.SetOwner($me)
$key.SetAccessControl($acl)

#After you have set owner you need to get the acl with the perms so you can modify it.
$acl = $key.GetAccessControl()

#Domain\user here is the one you are going to give permissions to
$rule = New-Object System.Security.AccessControl.RegistryAccessRule ("domain\user","FullControl","Allow")
$acl.SetAccessRule($rule)
$key.SetAccessControl($acl)

$key.Close()

,

3 Comments

How to Sync Samsung Galaxy Note with Exchange

(Pre-ICS)

Again another How To using Android on my newly acquired Samsung Galaxy Note, just because I love this phone so much!

How to sync Android with Exchange:

Open the settings menu and select “Accounts and Sync:

AndroidExch1

On the next screen select Add Account:

AndroidExch2

Next Select “Microsoft Exchange ActiveSync”:

AndroidExch3

Next Enter your Exchange email address and Password after you are done select Next in the bottom right:

AndroidExch4

Next you will see a status bar, unless you’ve typed a bad password:

AndroidExch5

Next you are going to see a warning about the fact that the Exchange Server now owns all kinds of security control over the phone.  This is normal, the long and short, the Exchange Admin now has the ability to remote wipe your device.  This is pretty standard especially for business that worry about security.  So just click ok.

AndroidExch6

Next you have the option to adjust settings on account behavior.  Things like How many days of email to keep on the phone “Period to sync email” or how many days to sync the Calendar “Period to sync Calendar”.  You also have the options to disable syncing contacts, calendar etc.  Marked in Green below.  You also have the option to send all email from this account which you may or may not want to do.  It all depends on if you have other email accounts setup on the phone (think gmail) and where you want most of your email to come from ie, gmail or exchange.  Make your choice and mark or don’t mark the item with the yellow arrow.  Then click Next.

AndroidExch7

Next you can give the account a name, this is simply a label you will use on your phone to recognize the account. The name of the business or school etc is a good choice here.

AndroidExch8

Once you are done you should see a list of accounts, typically Gmail and then the Exchange Account.  If you want to get back to the account settings to change something, Open the account so you are looking at the list of current emails.

Select the options button
Select “More”
Select “Account Settings”

From here you can now set custom sounds, signatures, etc for this specific account.

Good Luck!

,

Leave a comment

Powershell Script to Delete Exchange Mailboxes in Mass

By Request: How to delete a large number of mailboxes at once.

First, and I can not stress this enough, this script has the potential to delete production data, namely user and Exchange mailboxes. Please carefully consider the impact of this script before you use it. Make sure you have good backups of your User Accounts and Exchange Mailboxes before use. If it doubt, test with a single account before hand and/or use the -whatif flag. (More about this below) Ok now then, on to the good stuff.

There are a few ways you might approach the task of deleting mailboxes. Much of that comes in the form of how you come up with the list of mailboxes and/or users to delete.

This example assumes the following approach:

  • You are creating a text file with a list of accounts to remove.
  • You want to delete both the user and the mailbox.

So then to create a list of user and their mailboxes you want to delete, simply place a list of users in a text file one user per line. You might fetch the list using a Get-QADuser or Get-Mailbox as a filter, more on this later.

Example text file:

jsmith
msmith
jlittle

etc

Call the file MailboxesToDelete.txt and we’ll assume its on the C:\ drive.  Then create a script to run, in this example I’ll call it Delete_Mailboxes.ps1

#Add Exchanage snapin
add-pssnapin Microsoft.Exchange.Management.PowerShell.Admin

#Get list of mailboxes to delete
$users=Get-Content C:\MailboxesToDelete.txt

#For Loop to delete them
foreach ($user in $users)
{
#Print to screen user mailbox to delete
$user
#Delete AD user and Mailbox
Remove-Mailbox -Identity $user -Permanent $true -whatif

#Remove the -whatif if you want to really delete some users.
}

That is pretty much it.

You should then be able to type [PS]C:> Delete_Mailboxes.ps1 and delete users and their mailboxes based on the text file.

You might also, assuming you have some search criteria, use the Get-QADuser or Get-Mailbox command to filter out the list of users. Say all of those in a specific OU and turn this into a single one liner.

Example:

Get-QADUser -SearchRoot 'OU=INTERNATIONAL OFFICE USERS,DC=contoso,DC=com' | Remove-Mailbox -Identity $user -Permanent $true

Or you could use my script and simply Get-QADUser -SearchRoot ‘OU=INTERNATIONAL OFFICE USERS,DC=contoso,DC=com’ >> C:\MailboxesToDelete.txt and then run the above script. Again there are many ways to approach the actual search/list creation. This is just a few ways you might do it.

Be warned:
The -Permanent $true will not only delete the mailbox, it will also delete the user. If you don’t want the user account deleted and just the mailbox just remove -Permanet from the above or set it to $false.

If you just want to test at the end of the Remove-Mailbox statement put a -whatif at the end of the line.

Example:
Remove-Mailbox -id jsmith -whatif

I added “-whatif” to the script to hopefully save someone some pain while testing.  Remove it only when you are ready to actually delete some data.

Please reference: Technet if you have questions about the Remove-Mailbox command, it is a delete command so use with care.


, , ,

13 Comments

How To Change Apps in the Dock on a Samsung Galaxy Note

(Pre-ICS)

Simple and yet not so obvious effort with my new Samsung Galaxy Note.  Change the apps on the dock.

1. Click on the Applications button (Should be on the doc)

2. Click the Menu button.

3. Select Edit.

4. Drag the app you no longer want off the doc and then drag the one you want onto the dock

5. Click Menu button.

6. Click Save and your done.

You will also note the option to place a folder on the dock in place of a app if that is to your liking.

changedockapp1

,

Leave a comment

How to mount a Samsung Galaxy Note as a Mass USB Drive

Just picked up a new Samsung Galaxy Note Android phone with AT&T.  I’ve been using the iPhone for the past 4 or 5 years and have never branched out till now and there are some learning curves.  One of the 1st ones I ran into was trying to mount the Android device as a Mass USB drive.   The Samsung Note comes with software that auto mounts the device for general drive surfing right out of the box.  Some apps however require you to mount the device in Mass USB drive mode in order to sync to a associated desktop app.  After digging at it for a while I finally figured it out, so here is how it is done.

1. Unplug any USB cables

2. Go to the phones settings page and select Wireless and Networking

Settings

3.  Then select USB utilities

Settings USB

4. Press the “Connect storage to PC” button

USB mass storage

5. You will then get this image at which point you connect the USB cable to the phone.

USB popup

6.  After you connect the screen will change again and offer you yet another button.  “Connect USB Storage” – Press it.

USB Connected

At which point the little Android guy will turn Orange and you will be connected.

Android USB connected

(I wasn’t able to take a pic as the drive is locked for use by the PC at that point)

Hopefully you will find this useful as I did.

,

3 Comments

Powershell – Active Directory CSV User list for an Audit

If you ever have someone come along and ask for a full list of AD users, and they want to know if an account is disabled, LastLogon etc etc for say a Audit of some sort.  Here then is a simple one liner using Quest Software (Link over on my links page) Powershell add-on to do just that and export it to a csv for use in Excel.

Example

C:\>get-qaduser | select-object DisplayName, Description, Department, Manager, LogonName, AccountIsDisabled, LastLogonTimestamp, PasswordExpires, ParentContainer | export-csv C:\AD_Users.csv -NoTypeInformation

Then import the AD_Users.csv to excel and delimited by commas.

If you are interested in some other field you can look at your options by listing all the attributes for a single users like so:

C:\>get-qaduser username | fl

Leave a comment

PDFCreator – Handy PDF Print Server for Free

Recently I was asked to address a problem where remote users wanted to be able to print from a legacy Unix/Pick system that normally uses IP based printers.  The remote users connecting to the office using a client side VPN solution didn’t have access to a IP based Printer at home and needed another solution to get their printouts.  Management also didn’t want to spend a ton of money on the solution.  Working with the Unix team I came up with the solution to deploy a Microsoft Windows based PDF printer solution using PDFCreator (http://www.pdfforge.org/pdfcreator).  PDFCreator allows you to setup multiple printers that can be pre-configured to print PDFs to a specific file share that you as an admin can then manage share/file permission as normal.  Another benefit, you can configure these PDFs to be encrypted and have a password on them.  You can also manage if the PDFs can be printed or copied etc.

We ended up deploying this on its own file and print server and then mapping the users computers to their own individual share.  Then on the unix side we instructed them to print to a printer that was pointed back to a PDF printer set to print to their share.  Each user has their own PDF password as well to insure if they print to the wrong printer/share someone else couldn’t open their files.

Then I setup a simple windows script to wipe files contained in the shares older than 7 days.

There are a few catches which are not well covered in documentation which I outline below:

Here is a diagram sort of outlining what I’m talking about

The 1st Catch you need to setup PDFCreator to run as a service.  A good how to can be found over on this blog here.  In short:

  1. Install the Server 2003 resource kit (link).
  2. Create the service with SC:sc create pdfcreator start= auto binPath= “C:\Program Files\oldResourceKitTools\srvany.exe” DisplayName= “PDFCreator”Note the space between the equals sign and the value; it actually needs to be done that way, or SC won’t work.
  3. Check that that worked:sc query pdfcreator
  4. Mangle the service appropriately to actually run the server version of PDFCreator:Start the service and test it out – a file sent to the PDFCreator printer on the server should now pop out in whichever directory you specified back in step 1, regardless of whether or not anyone’s logged in at the server’s console.
    • Edit the key HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Services\pdfcreator.
    • Add a “Parameters” key.
    • Inside the newly-created key, add a REG_SZ value called “Application”, with the path to the PDFCreator executable as the data.
  5. Start the service and test it out – a file sent to the PDFCreator printer on the server should now pop out in whichever directory you specified back in step 1, regardless of whether or not anyone’s logged in at the server’s console.

The next Catch,  how to set a password on a individual PDF printer, again you have to edit the registry

So for example if you setup a printer and call it prITTEST (Used in my Example)  You would need to edit the key found at HKEY_LOCAL_MACHINE\SOFTWARE\Wow6432Node\PDFCreator\Profiles\prITTEST\Printing\Formats\PDF\Security

Then set the PDFOwnerPasswordString and PDFUserPasswordString with a password.  You also need to enable security by setting PDFOwnerPass, PDFUserPass, and PDFUseSecurity to 1.

One last thing of note, when installing PDFCreator, the ESET AV solution we use in the office reported the program containing a virus.  That said I tested the .exe using several other products and I think this is a false positive.  Likely flagging the Windows Tool bar it wants to install as spam-ware.

, , ,

Leave a comment

Citrix XenDesktop 5 using Machine Creation Services (MCS) and Microsoft KMS Services

Hey all, happy new year!   Been working on our XenDesktop deployment over the holidays and ran into a snafu when working with Microsoft Activation keys.  As any of you know when working with Microsoft products you have the option to use a MAK key or a KMS key with a given product.  However their is a limit on how many times you can use a MAK key and in large deployments this may not be the best solution. When deploying virtual desktops the best solution is to setup a Microsoft KMS host and use KMS client keys so that each clone will have a validate Windows License, this also prevents you from using up your MAK keys when you redeploy your clones during updates/patches/etc.

When we started down the path of using Citrix on top of VMware using MCS we didn’t realize at the time there was a catch using KMS keys.  Both Citrix and VMware when you deploy their solutions have options to reset the SID of the cloned machine however when you mix the two and use MCS it becomes a little more of a challenge.  I found a interesting statement of support from Citrix here: http://support.citrix.com/article/CTX128580

MCS does not support or work with KMS based Microsoft Windows 7 activation by default, however the following workaround has been provided and will be supported by Citrix Support should an issue arise.  So the process to address this while cover in the link in short is to create your image, create a snap shot, run slmgr /rearm from command line on the image, take a 2nd snap shot and label it rearm and then build your Machine Catalog off that.

After doing so, each clone as it boots up for the first time will have a unique sid to register with your KMS key server.

The down side is that anytime you want to update the image you have to perform the above steps all over again before updating the catalog when the updates be they windows updates, virus updates, putting a new icon on the desktop etc.

The whole process is much less of a issue if you have 25 other devices already registered with your KMS host as that is the minimal requirement to active Windows 7 using a KMS host prior to it actually allowing the 1st activation to be successful.  If this is the case then you need not bother with the above as the clones will still activate with the KMS host even if they have the same SID its the first 25 that is a gotcha.

, ,

Leave a comment