DCSIMG
August 2009 - Posts - Shay Levy

Shay Levy

If you repeat it, PowerShell it!

August 2009 - Posts

Get-WMIQualifierValue (revisited)

An updated version of my Get-WMIQualifierValue function. With this version you can query remote computers, specify the NameSpace of the class and also specify a property name to get just its values instead of all properties.

Sample Usage:

Get-WMIQualifierValue -Class Win32_LogicalDisk -ComputerName computer1 –Property StatusInfo

 

function Get-WMIQualifierValue
{

   param(
     
[string]$Class=$(Throw Parameter ‘Class’ cannot be empty),
      [string]$ComputerName=".",
      [string]$NameSpace="ROOT\cimv2",
      [
string]$Property="*"
  
)

   if($PSVersionTable)
   {
    
#PowerShell v2 detected 
    
$wmi = Get-WmiObject meta_class -Filter "__Class = '$class'" -Amended  ` 
   
-ComputerName $ComputerName -Namespace $NameSpace
   }
 
  
else
  
{
    
#PowerShell v1 detected
   
 $wmi=[wmiclass]"\\$ComputerName\$($NameSpace):$class" 
    
$wmi.psbase.options.useAmendedQualifiers=$true 
   }

   foreach ($p in $wmi.psbase.properties)
   {
     
$names = $p.qualifiers | ForEach-Object {$_.name}

      if($names -contains "values" -AND $names -contains "valuemap")
      {
        
$pLen = "-" * $p.name.length
        
$value = $p.qualifiers["Values"].value
        
$meaning = $p.qualifiers["ValueMap"].value
        
$map = $value | Select-Object Value,@{Name="Meaning";Expression={$_}}
        
1..$map.length | ForEach-Object { $map[$_-1].value=$meaning[$_-1] }
        
$map = $map | Add-Member NoteProperty Name $p.name –PassThru

         if($Property -eq "*")
         {
          
Write-Host ("`n$pLen`n"+$p.name+"`n$pLen")
          
$map | Select-Object Value,Meaning | Format-TableAutoSize 
         }

         if($p.name -eq $Property)
         {
          
Write-Host ("`n$pLen`n"+$p.name+"`n$pLen")
          
$map | Where-Object {$_.name -eq $Property } | Select-Object Value,Meaning | Format-Table –AutoSize
         
 break
        
}
      }
   }
}



                                            
            

Mailbox Users Storage limit

My morning task today includes the following: get all mailboxes (Exchange 2003) larger than X megs where the associated user mailbox storage limits are overriding the settings of the Mailbox store.

Storage limit information for user accounts is available in Active Directory Users and Computers on the user ‘Exchange General’ tab (click on ‘Storage Limits’ at the bottom). The ‘Storage Limits’ dialog box specifies the mailbox storage limits for warning or prohibiting a mailbox-enabled user from sending or receiving email. You can also use this dialog box to specify the number of days a deleted item is stored in the mailbox store before it is permanently deleted but for my task it is not needed.

So the script goes as follows:

  • Use WMI Get all mailboxes larger than 250MB in size.
  • Get the associated mailbox user from AD using Quest AD cmdlets.
  • Filter those which override the mailbox store policy (the checkbox, (1) in the figure above is not checked). The LDAP attribute name for the checkbox is mDBUseDefaults and the value is FALSE.

  • In addition, extend the filtered mailbox objects with storage limit attributes (and values):
    - Issue warning at (KB) – Ldap name (2) is mDBStorageQuota.
    - Prohibit send at (KB) – Ldap name (3) is mDBOverQuotaLimit.
    - Prohibit send and receive at (KB) – Ldap name (4) is mDBOverHardQuotaLimit.

$Server = "ExchangeServer"
$MbxSize= "250MB"

Get-WMIObject Exchange_Mailbox -Namespace root\MicrosoftExchangeV2 -Computer $server -Filter "size>=$($MbxSize/1kb)" | Foreach-Object {

  
$IncludedProperties = "mDBUseDefaults","mDBStorageQuota","mDBOverQuotaLimit","mDBOverHardQuotaLimit"
  
$user = Get-QADUser $_.LegacyDN -IncludedProperties $IncludedProperties

  
if(!$user.mDBUseDefaults)
   {
    
Add-member -InputObject $_ NoteProperty mDBUseDefaults $user.mDBUseDefaults
    
Add-member -InputObject $_ NoteProperty mDBStorageQuota $user.mDBStorageQuota
    
Add-member -InputObject $_ NoteProperty mDBOverQuotaLimit $user.mDBOverQuotaLimit
    
Add-member -InputObject $_ NoteProperty mDBOverHardQuotaLimit $user.mDBOverHardQuotaLimit –PassThru
   } 

} |
Select-Object MailboxDisplayName,Size,mDBUseDefaults,mDBStorageQuota,mDBOverQuotaLimit,mDBOverHardQuotaLimit

Force a VM to enter BIOS setup screen on next reboot

With the following PowerCLI filter you can force entry of virtual machine(s) into the BIOS setup screen next time the VM boots. You can configure the option in the VM options tab but with Set-VMBIOSSetup you can toggle the value programmatically:

Note that setting a VM to enter BIOS mode is a one time action. Once the VM reboots and enters the BIOS screen the ‘Force BIOS Setup’ flag is unchecked so that subsequent boots proceed normally.


filter Set-VMBIOSSetup
{
  
param(
        [
switch]$Disable,
        [
switch]$PassThru
   )

   if($_ -is [VMware.VimAutomation.Types.VirtualMachine])
    {
      
trap { throw $_ }       
       
      
$vmbo = New-Object VMware.Vim.VirtualMachineBootOptions
      
$vmbo.EnterBIOSSetup = $true
       
      
if($Disable)
        {
          
$vmbo.EnterBIOSSetup = $false
        }

      
$vmcs = New-Object VMware.Vim.VirtualMachineConfigSpec
      
$vmcs.BootOptions = $vmbo

        (
$_ | Get-View).ReconfigVM($vmcs)
       
      
if($PassThru)
        {
          
Get-VM $_
        }
    }
  
else
    {
      
Write-Error "Wrong object type. Only virtual machine objects are allowed."
    }
}


Sample usage:

## Get all VMs which name starts with XP, force the VM to enter into bios
## mode on next boot and write VM objects back to pipeline

Get-VM XP* | Set-VMBIOSSetup -PassThru

# Get all VMs which name starts with XP and disable (uncheck) bios mode on next boot
Get-VM XP* | Set-VMBIOSSetup -Disable

One thing I found when testing the filter on ESXi 4 is that you get an error ‘fault.RestrictedVersion.summary’ if ESXi is registered, surprisingly it works if ESXi 4 is not registered. Duh!

 

New PowerShell videos

via @makovec

Osama Sajid, PowerShell Program Manager, and Jeffrey Snover , Architect of PowerShell and Microsoft Distinguished Engineer,  discussing the foundations and vision for PowerShell as a critical component of Microsoft's platform management strategy.

 

Discussions with the Architect, Part 1
Discussions with the Architect, Part 2
Discussions with the Architect, Part 3

 

And two more with James Brundage, PowerShell Test Team SDE:

PowerShell "How-To" : Variables, Types, and Operators
PowerShell "How-To" : Arrays, Conditionals, Collections, and Loops

Exchange 2007 SP2

Exchange 2007 SP2 was released yesterday (version 08.02.0176.002).  Below is some information regarding this release. 

Exchange 2007 SP2 Download

Microsoft Exchange Server 2007 Service Pack 2 (SP2) has been designed specifically to help meet the challenges of any business and the needs of all the different groups with a stake in the messaging system. Exchange Server 2007 SP2 is a mission-critical communications tool that enables employees to be more productive and access their information anywhere and anytime while providing a messaging system that enables rich, efficient access to e-mail, calendar items, voice mail, and contacts. For the administrator, Exchange Server 2007 SP2 provides advanced protection options against e-mail security threats, such as spam and viruses, as well as the tools to help manage internal compliance and high availability needs.

For an overview of the new features that are available in Exchange Server 2007 SP2, see "What's New in Exchange Server 2007 SP2".

Release Notes:
http://www.microsoft.com/downloads/details.aspx?FamilyID=ee7829a3-0ae8-44de-822c-908cd1034523&displaylang=en

Active Directory Schema Changes:
http://technet.microsoft.com/en-us/library/ee221142.aspx

 

Active Directory PowerShell scripts pack

idera

As announced yesterday, Idera, the company behind PowerShellPlus , has released the Active Directory scripts pack. The scripts pack, authored by Aleksandar Nikolic and myself, is a set of more than 30 PowerShell 1.0 ADSI functions and filters designed to help IT administrators automate everyday Active Directory management tasks.

You can download the scripts pack HERE (registration needed). We hope you'll find it useful and if you have any questions or find any bugs you can report them to one of us. We are also available on Twitter (@alexandair and @ShayLevy).

Where do the functions come from?

With PowerShell 2.0 you can tell exactly where a function came from, whether the function was defined in your profile or dot-sourced in a script file. You may find it useful when you want to edit a function source code but don’t know or remember the function source file. 

The one-liner below gets all functions from the built-in Function provider (contains a view of the functions stored in session state), filters just those that have a value in the ScriptBlock.File member and creates a new calculated property to display the location of the file the function came from.

Get-ChildItem Function: | Where-Object {$_.ScriptBlock.File} | Select-Object Name,@{Name="Location";Expression={$_.ScriptBlock.File}}

Powershell v2 for Vista and Windows Server 2008


PowerShell v2 is now available for download for Windows Vista and Windows Server 2008.
Windows XP and Windows Server 2003 SP2 are not included in this RC release but they will be made available in future.

For more information, and download link, see the PowerShell team blog announcement.

Exchange White Space

A common posting on PowerShell newsgroups and forums from Exchange administrators is how to parse event id 1221 from the Exchange server application log file. A typical event message would look like:

Event Type:  Information
Event Source: MSExchangeIS Mailbox Store
Event Category: General 
Event ID: 1221
Date:  10/01/2009
Time: 13:27:31
User:  N/A
Computer: SERVER
Description: The database "First Storage Group\Mailbox Store (SERVER)" has
7.2 megabytes of free space after online defragmentation has terminated.

Usual solutions are based on regular expressions to process the message description and extract the name of the database(s) and the number of free megabytes. The bellow code gets the information and doesn’t require any knowledge of regular expression, though I strongly recommend any sys admin getting to know regex!

The message text is a fixed message with two placeholders for the database name and the free megabytes:

  The database "<name>" has “<number>” megabytes of free space after online defragmentation has terminated.

We can access the message placeholder values with the insertion strings array property of the Windows NT event object:

Get-WMIObject Win32_NTLogEvent -ComputerName SERVER -Filter "LogFile='Application' AND `
EventCode=1221 AND TimeWritten>='$Start' AND TimeWritten<='$End'" | `
Select-Object  ComputerName,InsertionStrings

ComputerName InsertionStrings
------------ ----------------
SERVER       {10351, First Storage Group\SG1 (SERVER)}
SERVER       {6043, Second Storage Group\SG2 (SERVER)}
SERVER       {881, Third Storage Group\SG3 (SERVER)}

As you can see, the free megs are positioned at index 0 and the database name at 1. With Get-ExchangeWhiteSpace we can pass a computer name and get white space information for the previous day. 

function Get-ExchangeWhiteSpace {

param(
  
$ComputerName = $(throw "ComputerName cannot be empty.")
)

# Convert Dates to WMI CIM dates
$tc = [System.Management.ManagementDateTimeconverter]
$Start =$tc::ToDmtfDateTime( (Get-Date).AddDays(-1).Date )
$End =$tc::ToDmtfDateTime( (Get-Date).Date)

# Create two claculated properties for InsertionStrings values
$DB = @{Name="DB";Expression={$_.InsertionStrings[1]}}
$FreeMB = @{Name="FreeMB";Expression={[int]$_.InsertionStrings[0]}}

Get-WMIObject Win32_NTLogEvent -ComputerName $ComputerName -Filter "LogFile='Application' AND EventCode=1221 AND TimeWritten>='$Start' AND TimeWritten<='$End'" | Select-Object ComputerName,$DB,$FreeMB | Sort-Object FreeMBUnique Descending

}

 

PS > Get-ExchangeWhiteSpace -ComputerName SERVER | Format-Table -AutoSize

ComputerName DB                                FreeMB
------------ --                                ------
SERVER       First Storage Group\SG1(SERVER)   10351
SERVER       Second Storage Group\SG2(SERVER)  6043
SERVER       Third Storage Group\SG3(SERVER)   881

PowerGUI 1.9 is now available

pg

PowerGUI 1.9 has been released.
Read the full announcement on Dmitry's blog.

How to inform users that their password is about to expire

I got several requests to publish the latest version of a script I wrote once to retrieve all mail enabled user accounts that have the password configured to never expire. Once the accounts are retrieved, based on the DaysToExpire variable value, a mail message is sent to the users stating that their password will expire in X days.

Notice that the script requires the latest version of Quest AD cmdlets and is also compatible with PowerShell version 1 or 2.



$ReqVersion = [version]"1.2.2.1254"
$QadVersion = (Get-PSSnapin Quest.ActiveRoles.ADManagement).Version

if($QadVersion -lt $ReqVersion)
{
   
throw "Quest AD cmdlets version '$ReqVersion' is required. Please download the latest version"
}


function Send-Mail
{
  
param($SmtpServer,$From,$To,$Subject,$Body)

  
$smtp = new-object system.net.mail.smtpClient($SmtpServer)
  
$mail = new-object System.Net.Mail.MailMessage
  
$mail.from= $From
  
$mail.to.add($To)
  
$mail.subject= $Subject
  
$mail.body= $Body
  
$smtp.send($mail)
}


$MaxPassAge = (Get-QADObject (Get-QADRootDSE).defaultNamingContextDN).MaximumPasswordAge.days

if($MaxPassAge -le 0)

  
throw "Domain 'MaximumPasswordAge' password policy is not configured."
}

$DaysToExpire = 14 
$MailForm = "you@domain.com"
$PSEmailServer = "exServerName"

Get-QADUser -Enabled -PasswordNeverExpires:$false -SizeLimit 0 -Email * |`
Select-Object Name,Email,@{Name="Expires";Expression={ $MaxPassAge - $_.PasswordAge.days }} |`
Where-Object {$_.Expires -gt 0 -AND $_.Expires -le $DaysToExpire } | Foreach-Object {
 
 
$Subject="Password reminder: Your Windows password will expire in $($_.Expires) days"
 
 
if($PSVersionTable)
  {
    
# PowerShell Version 2 detected  
     Send-MailMessage -From $MailForm -To $_.Email -Subject  $Subject -Body  $Subject 
  }
 
else
  {
    
# code for PowerShell v1
     Send-Mail -SmtpServer $PSEmailServer -From $MailForm -To  $_.Email -Subject  $Subject -Body  $Subject
  }

}