Get-Mailbox | Where {$_.ForwardingAddress -ne $null} | Select Name, ForwardingAddress, DeliverToMailboxAndForward
Blog view of all posts
Import a list of users and export a list with more fields
# Make utf8 to include special characters
cat .\list.csv > .\list2.csv
# Import the file and process export as utf8
Import-Csv .\list2.csv | foreach {
Get-QADUser -lastname $_.lastname -firstname $_.firstname | select firstname,lastname,mobile,primarysmtpaddress,logonname
} | Export-Csv .\list3.csv -Encoding “UTF8″
Add “+47″ to mobile field on all users missing it in AD
# Add +47 in “mobile”
$Users = Get-QADUser -SearchRoot “domain/A1/users” -sizelimit 0 | where { $_.mobile.length -eq 8 }
foreach ($user in $users) {
Set-QADUser -id $user -mobile ($user.mobile.insert(0,’+47′))
}
Count users with 8 characters mobile field in AD
# Number of users with 8 characters mobile
(Get-QADUser -sizelimit 0 | where { $_.mobile.length -eq 8 }).count
Remove whitespaces in mobile field in AD
# Remove whitespaces in mobile
$Users = Get-QADUser -SearchRoot “domain/A1/users” -sizelimit 0 | where {$_.mobile -match “\s”}
foreach ($user in $users) {
Set-QADUser -id $user -mobile ($user.mobile -replace “\s”)
}
Count all users with whitespaces in mobile field in AD
# Count users with whitespace in mobile
(Get-QADUser -sizelimit 0 | where {$_.mobile -match “\s”}).count
See mailboxsize on a specific database and sort by size
Get-Mailbox -Database DATABASE | Get-MailboxStatistics | select displayname,ItemCount,totalitemsize | sort TotalItemSize
Count members of dynamic distribution group
# Count members of the distrogroup
$members = Get-DynamicDistributionGroup -Identity “Groupname”
(Get-Recipient -RecipientPreviewFilter $members.RecipientFilter).count
Clear completed move requests on Exchange 2010
Get-MoveRequest -MoveStatus Completed | Remove-MoveRequest
List all mailaddresses of members in a distributionlist
Get-DistributionGroup DISTROLIST | get-distributiongroupmember | select primarysmtpaddress | export-csv c:\temp\list.csv
Excel shortcuts
To select a row
SHIFT-SPACE
To delete a row
CTRL- -
Clean up user accounts in one OU after linked-mailbox migration to new domain
This script uses the Quest AD Cmdlets that can be downloaded free from Quest.
# Add the Quest commandlets if not added if(!(Get-PSSnapin | Where-Object {$_.name -eq "quest.activeroles.admanagement"})) { ADD-PSSnapin Quest.Activeroles.ADManagement } # Add Exchange 2010 commandlets (if not added) if(!(Get-PSSnapin | Where-Object {$_.name -eq "Microsoft.Exchange.Management.PowerShell.E2010"})) { ADD-PSSnapin Microsoft.Exchange.Management.PowerShell.E2010 } ################## SETTINGS # Home directory for users $homedir = "\\contoso.com\users\" # Domain $domain = "contoso.com" # Email address to keep $keepmail = "@contoso.com" # The OU we are working on $OU = "contoso.com/Users/migrated_users" ################## # Run on all users in the defined OU Get-QADUser -SearchRoot $OU | foreach { echo "-------------------------------------------------" echo "Working on $($_.displayname)" echo "-------------------------------------------------" # Generate username after the 3+3 rule $userprincipalname = ($_.firstname.substring(0,3) + $_.lastname.substring(0,3)).tolower() $userprincipalname = $userprincipalname.replace("ø","o") $userprincipalname = $userprincipalname.replace("å","a") $userprincipalname = $userprincipalname.replace("æ","e") # Make the changes on the user account Set-QADUser -Identity $_ -UserPrincipalName $($userprincipalname + "@" + $domain) -SamAccountName "$($userprincipalname)" -HomeDirectory $($homedir + $userprincipalname) -HomeDrive "H:" #-whatif # Check to see if the users homedirectory exists if ( !(Test-Path -Path "$homedir\$userprincipalname" -PathType Container) ) { # Doesn't exist so create it. Write-Host "home directory doesn't exist. Creating home directory." # Create the directory New-Item -path $homedir -Name $userprincipalname -ItemType Directory $userDir = "$homedir\$userprincipalname" # Modify Permissions on homedir $Rights= [System.Security.AccessControl.FileSystemRights]::Read -bor [System.Security.AccessControl.FileSystemRights]::Write -bor [System.Security.AccessControl.FileSystemRights]::Modify -bor [System.Security.AccessControl.FileSystemRights]::FullControl $Inherit=[System.Security.AccessControl.InheritanceFlags]::ContainerInherit -bor [System.Security.AccessControl.InheritanceFlags]::ObjectInherit $Propogation=[System.Security.AccessControl.PropagationFlags]::None $Access=[System.Security.AccessControl.AccessControlType]::Allow $AccessRule = new-object System.Security.AccessControl.FileSystemAccessRule("$userprincipalname",$Rights,$Inherit,$Propogation,$Access) $ACL = Get-Acl $userDir $ACL.AddAccessRule($AccessRule) $Account = new-object system.security.principal.ntaccount($userprincipalname) $ACL.setowner($Account) $ACL.SetAccessRule($AccessRule) Set-Acl $userDir $ACL } # We need some sleep... start-sleep -sec 20 # Now we need to clean up the users Exchange account Get-Mailbox -Identity $userprincipalname | # Loop through all the emailaddresses foreach { $a = $_.emailaddresses $b = $_.emailaddresses # Remove all but $keepmail foreach($e in $a) { if ($e.tostring() -notmatch $keepmail ) { $b -= $e; } $_ | Set-mailbox -EmailAddressPolicyEnabled $false -emailaddresses $b -alias $userprincipalname } } # We had to remove the emailaddresspolicy to make changes. Let's reactivate it Set-mailbox -Identity $userprincipalname -EmailAddressPolicyEnabled $true }
Delete all email addresses but one on a mailbox
Get-Mailbox -Identity $userprincipalname | # Loop through all the emailaddresses foreach { $a = $_.emailaddresses $b = $_.emailaddresses # Remove all but $keepmail foreach($e in $a) { if ($e.tostring() -notmatch $keepmail ) { $b -= $e; } $_ | Set-mailbox -EmailAddressPolicyEnabled $false -emailaddresses $b -alias $userprincipalname } } # We had to remove the emailaddresspolicy to make changes. Let's reactivate it Set-mailbox -Identity $userprincipalname -EmailAddressPolicyEnabled $true }
Easier ForEach/Where-Object in Powershell V3
PowerTip of the Day, from PowerShell.com
In the upcoming PowerShell v3 which you can already download as a Beta version, using Where-Object and ForEach-Object becomes a lot simpler. No longer do you need a script block and code. This, for example, is all you need to find files larger than 1MB:
Get-ChildItem $env:windir | Where-Object Length -gt 1MB
Previously, you would have had to write:
Get-ChildItem $env:windir | Where-Object { $_.Length -gt 1MB }
Creating home directory for user
When setting the -homedirectory switch on a user through Powershell the directory is not created.
Use this code to create the folder and apply the necessary ACLs:
if ( !(Test-Path -Path "$homedir\$userprincipalname" -PathType Container) ) { ## Doesn't exist so create it. Write-Host "home directory doesn't exist. Creating home directory." ## Create the directory New-Item -path $homedir -Name $userprincipalname -ItemType Directory $userDir = "$homedir\$userprincipalname" ## Modify Permissions on homedir $Rights= [System.Security.AccessControl.FileSystemRights]::Read -bor [System.Security.AccessControl.FileSystemRights]::Write -bor [System.Security.AccessControl.FileSystemRights]::Modify -bor [System.Security.AccessControl.FileSystemRights]::FullControl $Inherit=[System.Security.AccessControl.InheritanceFlags]::ContainerInherit -bor [System.Security.AccessControl.InheritanceFlags]::ObjectInherit $Propogation=[System.Security.AccessControl.PropagationFlags]::None $Access=[System.Security.AccessControl.AccessControlType]::Allow $AccessRule = new-object System.Security.AccessControl.FileSystemAccessRule("$userprincipalname",$Rights,$Inherit,$Propogation,$Access) $ACL = Get-Acl $userDir $ACL.AddAccessRule($AccessRule) $Account = new-object system.security.principal.ntaccount($userprincipalname) $ACL.setowner($Account) $ACL.SetAccessRule($AccessRule) Set-Acl $userDir $ACL }
Thank you very much for this tip Shay Levy!
BgPing – A High Performance Bulk Ping Utility

xb90 from Posh Tips has written a gorgeous masterpiece; BgPing.
Description from Posh Tips:
“BgPing.ps1 is a Background Ping Script capable of pinging enormous hosts lists in record time. You could call it a Bulk Ping Script, a Mass Ping Script, a Batch Ping Script or even a Mega Ping Script but the bottom line is: this baby will crank through a lot of IP addresses (or hostnames) very quickly.”
Connect to different domain controller
Connect-QADService -service ‘server.company.com’
This requires the Quest commandlets.
Create mailbox to all users in a CSV based on the 3+3 naming policy
# Create mailbox to all users in a CSV based on the 3+3 naming policy. # This will also create the user in AD $parentcontainer = "contoso.com/container" $homedirectory = "\contoso.com\users\$username" # Prompt the user for password $password = Read-Host "Enter password" -AsSecureString # The following has to be done to import with european characters cat "c:\temp\users.csv" > c:\temp\listtemp.csv # Loop through the list and # - replace european letters with o,a or e. # - create username based on the 3+3 naming convention # (three first letters in the firstname and lastname.) # - all lower case import-csv c:\temp\listtemp.csv | foreach { $username = ($_.firstname.substring(0,3) + $_.lastname.substring(0,3)).tolower() $username = $username.replace("ø","o") $username = $username.replace("å","a") $username = $username.replace("æ","e") # The following line can create the user if you do not need mailbox. # new-qadUser -ParentContainer $parentcontainer -FirstName $_.firstname -LastName $_.lastname -DisplayName $($_.FirstName + " " + $_.LastName) -SamAccountName $username -Name $username -UserPrincipalName ($username + '@contoso.com') -whatif # Create the mailbox New-Mailbox -Alias $username -Name $($_.FirstName + " " + $_.LastName) -OrganizationalUnit $parentcontainer -UserPrincipalName ($username + '@contoso.com') -SamAccountName $username -FirstName $_.firstname -LastName $_.lastname -ResetPasswordOnNextLogon $false -password $password -whatif }
Adding snapins/modules to PowerShell
# Import the ActiveDirectory cmdlets Import-Module ActiveDirectory # List available snapins on your system: Get-PSSnapin # List registered snapins Get-PSSnapin -Registered # Alias: gsnp # Add Snapin: Add-PSSnapin # Examples: Add-PSSnapin Microsoft.Exchange.Management.PowerShell.Admin # Exchange 2007 Add-PSSnapin Microsoft.Exchange.Management.PowerShell.E2010 # Exchange 2010 Add-PSSnapin Microsoft.SystemCenter.VirtualMachineManager # WMM (Hyper-V) Add-PSSnapin Quest.Activeroles.ADManagement # Quest commandlets
(You can download the Quest Commandlets from here.)
You will get an error if you try to add a snapin that is already added. Your script will continue to run but you'll have a bunch of nasty red letters in your shell. Not too sexy, eh? The way to avoid this is to first check if the snapin is loaded and then only load if it is not.
Do it like this:
# Add Exchange 2007 commandlets (if not added) if(!(Get-PSSnapin | Where-Object {$_.name -eq "Microsoft.Exchange.Management.PowerShell.Admin"})) { ADD-PSSnapin Microsoft.Exchange.Management.PowerShell.Admin } # Add Exchange 2010 commandlets (if not added) if(!(Get-PSSnapin | Where-Object {$_.name -eq "Microsoft.Exchange.Management.PowerShell.E2010"})) { ADD-PSSnapin Microsoft.Exchange.Management.PowerShell.E2010 } # Add Virtual Machine Manager (Hyper-V) commandlets (if not added) if(!(Get-PSSnapin | Where-Object {$_.name -eq "Microsoft.SystemCenter.VirtualMachineManager"})) { ADD-PSSnapin Microsoft.SystemCenter.VirtualMachineManager } # Add Quest commandlets (if not added) if(!(Get-PSSnapin | Where-Object {$_.name -eq "Quest.Activeroles.ADManagement"})) { ADD-PSSnapin Quest.Activeroles.ADManagement }
Head on over to http://blogs.technet.com/b/heyscriptingguy/archive/2010/10/16/learn-how-to-load-and-use-powershell-snap-ins.aspx to learn more about snapins.
Launching remote desktop from the command line
The remote desktop connection dialog box provides you with everything that you need to configure and connect to another computer capable of RDP. You can use the Save As button on the Connection Settings panel to save all your connection settings as an RDP file. Then, you can launch and connect to a remote computer simply by double-clicking the RDP file.
You can also script a remote desktop connection. The remote desktop connection executable file is MSTSC.EXE, and the following are some of the most common parameters:
- /v:<computername>–specifies the name of the computer to connect to.
- /f–starts the connection in a full screen.
- /w:<width>–specifies the width of the remote desktop screen.
- /h:<height>–specifies the height of the remote desktop screen.
- /admin – connects with admin rights
- /console – connects to the console of a Windows Server 2003 based system
For example, to remotely connect to a computer named Kaltec in a 640 x 480 remote desktop screen, you would use the following command:
mstsc /v: Kaltec /w:640 /h:480
You can type this command line in the Run dialog box, as well as use it in a batch file.
mstsc.exe {ConnectionFile | /v:ServerName[:Port]} [/console] [/f] [/w:Width/h:Height]
Display size of cluster shared volumes
Import-Module FailoverClusters $objs = @() $csvs = Get-ClusterSharedVolume foreach ( $csv in $csvs ) { $csvinfos = $csv | select -Property Name -ExpandProperty SharedVolumeInfo foreach ( $csvinfo in $csvinfos ) { $obj = New-Object PSObject -Property @{ Name = $csv.Name Path = $csvinfo.FriendlyVolumeName Size = $csvinfo.Partition.Size FreeSpace = $csvinfo.Partition.FreeSpace UsedSpace = $csvinfo.Partition.UsedSpace PercentFree = $csvinfo.Partition.PercentFree } $objs += $obj } } $objs | ft -auto Name,Path,@{ Label = "Size(GB)" ; Expression = { "{0:N2}" -f ($_.Size/1024/1024/1024) } },@{ Label = "FreeSpace(GB)" ; Expression = { "{0:N2}" -f ($_.FreeSpace/1024/1024/1024) } },@{ Label = "UsedSpace(GB)" ; Expression = { "{0:N2}" -f ($_.UsedSpace/1024/1024/1024) } },@{ Label = "PercentFree" ; Expression = { "{0:N2}" -f ($_.PercentFree) } }
Last logged on time of a user
Get-QADUser "UserName" | Format-Table -Property @{Label='LastLogonLocal';Expression={$_.lastLogon.ToLocalTime()}}
(Requires Quest AD cmdlets)
Check size of users mailbox and sort on size on a specific database
Get-MailboxStatistics -Database "YOURDATABASE" | Sort-Object TotalItemSize –Descending | ft @{label=”User”;expression={$_.DisplayName}},@{label="Total Size (MB)";expression={$_.TotalItemSize.Value.ToMB()}},@{label=”Items”;expression={$_.ItemCount}},Database
Hide contact from Global Addresslist (GAL)
get-mailcontact "yourcontact" | Set-mailContact -HiddenFromAddressListsEnabled $true
WebExplorer
WebExplorer is a Windows Explorer style file manager through your webbrowser, but don’t let the “Windows part” of it scare you away! Just upload the file to your designated “admin” directory on your PHP enabled website, edit the variable $basedir to reflect your website, and off you go!!
This application lets you edit, browse, CHMOD, view, move, rename, copy, and create files/directories in any forms/tables enabled browser. You even have the option to create html skeleton-files.
I haven’t done any work on WebExplorer since 2002 so it can be considered abandonware. But feel free to use.
What does WebExplorer require?
Webserver with PHP3 or newer installed
How about security?
WebExplorer does not have any “built in” authorization function. Use HTAccess or similar for this.
Can you develop blah blah or make WebExplorer do yaddayadda?
Donate first, ask later.
Do you support WebExplorer?
See previous q/a
How many downloads?
Lost track a long time ago… I’d guess around 35 000.
Download
webexplorer20.zip
webexplorer20.tar.gz
Disable email addresspolicy on all contacts in one OU
Get-mailcontact -OrganizationalUnit "contoso.com/path/to/ou" | Set-mailContact -EmailAddressPolicyEnabled $false -whatif
Hide all contacts in one OU from addresslist
get-mailcontact -OrganizationalUnit "contoso.com/path/to/ou" | Set-mailContact -HiddenFromAddressListsEnabled $true -whatif
Delete one email address from all contacts in one OU
get-mailcontact -OrganizationalUnit "contoso.com/path/to/ou" | foreach { $a = $_.emailaddresses $b = $_.emailaddresses foreach($e in $a) { if ($e.tostring() -match "@emailtoremove.com") { $b -= $e; } } $_ | Set-mailContact -emailaddresses $b } -whatif }
Keyboard Tricks for Launching PowerShell
PowerTip of the Day, from PowerShell.com:
If you have pinned PowerShell to your taskbar (on Windows 7: launch PowerShell, right-click its icon in the task bar, choose “Pin this program to taskbar”), then a click on the icon will open PowerShell. Here are three neat tricks:
First, move the pinned PowerShell icon with your mouse to the leftmost position in your taskbar. Yes, icons are movable! Now, press WIN+1. PowerShell will launch or jump into the foreground, just as if you had clicked the PowerShell icon.
Next, press SHIFT+WIN+1 (or hold SHIFT while you click your PowerShell icon). You get a new PowerShell window.
Finally, hold CTRL+SHIFT+WIN+1 (watch your fingers). This time, PowerShell starts elevated (provided Windows uses UAC).
As you may have guessed, the number reflects the icon position, so pressing a “2″ instead of a “1″ applies your keyboard magic to the second icon in your taskbar.
Using PowerShell ISE with Full Privileges
PowerTip of the Day, from PowerShell.com:
Sometimes you need full administrator privileges to debug or test a script in the ISE script editor. By default, ISE starts with restricted privileges (when Windows User Account Control (UAC) is enabled).
To launch ISE with full privileges, right-click the PowerShell icon in your taskbar, and hold CTRL+SHIFT while you click on it. This key shortcut works for anything you click and invokes the UAC elevation dialog.
Implicit Foreach in PSv3
PowerTip of the Day, from PowerShell.com:
PowerShell v3 Beta is available for quite some time now, so every now and then we start tossing in some PowerShell v3 tips. We’ll clearly mark them as such since they only run on PowerShell v3, not v2. This is something new in PowerShell v3:
When you work with array data, in previous PowerShell versions you had to loop through all elements to get to their properties and methods. No more in PowerShell v3. PowerShell now detects that you are working with an array and applies your call to all array elements. So with this line you could gracefully close all running notepad.exe.
(Get-Process notepad).CloseMainWindow()
Previously, you would have had to write:
Get-Process notepad | ForEach-Object { $_.CloseMainWindow() }
Export-CSV with append
function Export-CSV { [CmdletBinding(DefaultParameterSetName='Delimiter', SupportsShouldProcess=$true, ConfirmImpact='Medium')] param( [Parameter(Mandatory=$true, ValueFromPipeline=$true, ValueFromPipelineByPropertyName=$true)] [System.Management.Automation.PSObject] ${InputObject}, [Parameter(Mandatory=$true, Position=0)] [Alias('PSPath')] [System.String] ${Path}, #region -Append (added by Dmitry Sotnikov) [Switch] ${Append}, #endregion [Switch] ${Force}, [Switch] ${NoClobber}, [ValidateSet('Unicode','UTF7','UTF8','ASCII','UTF32', 'BigEndianUnicode','Default','OEM')] [System.String] ${Encoding}, [Parameter(ParameterSetName='Delimiter', Position=1)] [ValidateNotNull()] [System.Char] ${Delimiter}, [Parameter(ParameterSetName='UseCulture')] [Switch] ${UseCulture}, [Alias('NTI')] [Switch] ${NoTypeInformation}) begin { # This variable will tell us whether we actually need to append # to existing file $AppendMode = $false try { $outBuffer = $null if ($PSBoundParameters.TryGetValue('OutBuffer', [ref]$outBuffer)) { $PSBoundParameters['OutBuffer'] = 1 } $wrappedCmd = $ExecutionContext.InvokeCommand.GetCommand('Export-Csv', [System.Management.Automation.CommandTypes]::Cmdlet) #String variable to become the target command line $scriptCmdPipeline = '' # Add new parameter handling #region Dmitry: Process and remove the Append parameter if it is present if ($Append) { $PSBoundParameters.Remove('Append') | Out-Null if ($Path) { if (Test-Path $Path) { # Need to construct new command line $AppendMode = $true if ($Encoding.Length -eq 0) { # ASCII is default encoding for Export-CSV $Encoding = 'ASCII' } # For Append we use ConvertTo-CSV instead of Export $scriptCmdPipeline += 'ConvertTo-Csv -NoTypeInformation ' # Inherit other CSV convertion parameters if ( $UseCulture ) { $scriptCmdPipeline += ' -UseCulture ' } if ( $Delimiter ) { $scriptCmdPipeline += " -Delimiter '$Delimiter' " } # Skip the first line (the one with the property names) $scriptCmdPipeline += ' | Foreach-Object {$start=$true}' $scriptCmdPipeline += '{if ($start) {$start=$false} else {$_}} ' # Add file output $scriptCmdPipeline += " | Out-File -FilePath '$Path'" $scriptCmdPipeline += " -Encoding '$Encoding' -Append " if ($Force) { $scriptCmdPipeline += ' -Force' } if ($NoClobber) { $scriptCmdPipeline += ' -NoClobber' } } } } $scriptCmd = {& $wrappedCmd @PSBoundParameters } if ( $AppendMode ) { # redefine command line $scriptCmd = $ExecutionContext.InvokeCommand.NewScriptBlock( $scriptCmdPipeline ) } else { # execute Export-CSV as we got it because # either -Append is missing or file does not exist $scriptCmd = $ExecutionContext.InvokeCommand.NewScriptBlock( [string]$scriptCmd ) } # standard pipeline initialization $steppablePipeline = $scriptCmd.GetSteppablePipeline( $myInvocation.CommandOrigin) $steppablePipeline.Begin($PSCmdlet) } catch { throw } } process { try { $steppablePipeline.Process($_) } catch { throw } } end { try { $steppablePipeline.End() } catch { throw } } }





