‘Remoting is one of the most anticipated new features in Windows PowerShell 2.0. It turns Windows Powershell into an industrial strength management platform by enabling users to run Windows PowerShell commands on remote machines throughout the enterprise. However, setting up PowerShell remoting can be a daunting task. This guide helps users understand the concepts of remoting and provides essential and practical advice on setup, deployment and security.’
The ‘Administrator's Guide To Windows PowerShell Remoting‘ is a must read document, written by PowerShell MVPs Dr. Tobias Weltner (who is also the brilliant mind behind PowerShellPlus) and Aleksandar Nikolic, along with Richard Giles (Product Manager at Idera). The guide is available for free to all PowerShell.com members. So, if you're not a member already… now is time to join!
With the following PowerShell one-liner you can check if the machine you’re working on has internet connectivity. The result is a Boolean value. If TRUE, the local machine is connected to the internet; if FALSE, it is not.
Minimum supported client: Windows Vista
[Activator]::CreateInstance([Type]::GetTypeFromCLSID([Guid]'{DCB00C01-570F-4A9B-8D69-199FDBA5723B}')).IsConnectedToInternet
A member of my team came in this morning with a scripting request:
"If we ran a full backup on all of our servers (fixed disks), how much disk space would they all consume altogether? We need to give the boss a ‘ball-park number’ by the end of the day!"
So, how can we get that number? Here’s a quick & dirty version.
1. Get all computers objects (names only). We keep our servers in a dedicated OU in active directory.
2. Run a WMI query on all servers and subtract each fixed disk FreeSpace from the total disk size.
3. Use Measure-Object to compute the sum of all of the values from the previous step.
4. Print the result in TB.
$servers = Get-QADComputer -SizeLimit 0 –SearchRoot ‘Domain.com/Servers’ | Select-Object -ExpandProperty Name
$disks = Get-WMIObject Win32_LogicalDisk -Filter "DriveType=3" -ComputerName $servers -ErrorAction SilentlyContinue | Foreach-Object { $_.Size - $_.FreeSpace }
$totalDiskSpace = $Disks | Measure-Object -Sum
$totalDiskSpace.Sum/1TB
That wasn’t that hard. Needless to say, our boss didn’t have to wait all day long, he got the answer after only a few minutes!
EDIT: I've been asked about a way to get the server names without third party cmdlets.
The following shows how you can use the DirectorySearcher class. We initialize a new DirectorySearcher object and supply to arguments: Filter and PropertiesToLoad. The SearchRoot property tells the searcher where to start the search from (Servers OU).
$searcher = New-Object System.DirectoryServices.DirectorySearcher ‘(&(objectCategory=Computer)(objectClass=User))',’name’
$searcher.SearchRoot= "LDAP://OU=Servers,DC=domain,DC=com"
$servers = $searcher.FindAll() | Foreach-Object { $_.Properties["name"] }
iPowerShell V1 was the first application I installed on my iPhone and V2 is now available at the Apple app store. It is an easy to use reference tool for users of Microsoft's PowerShell scripting language for use on the iPhone or iPod Touch, It's FREE! If you already have iPowerShell V1 you should just be able to download the update. If you are not familiar with this wicked, cool product, check out SAPIEN’s blog post and read all about it.
Have you ever read Help that wasn't really helpful? Here's your chance to fix it.
The Windows PowerShell Community Review process is looking for volunteers for the third documentation review cycle – especially beginners and intermediate PowerShell users and people with little or no programming background.
The Windows PowerShell documentation team and PowerShellCommunity.org jointly sponsor the Windows PowerShell Community Doc Review. As a member, you'll get to read and comment on the Help docs before they're published, and work with the writers, editors, and the product team to make sure every word is really helpful.
”We're looking for users at all experience levels and with all different backgrounds, but we love to have beginners, people with no programming experience, people who know other scripting languages or shells, and people who are not native English speakers. If you're a system admin and you don't really know Windows PowerShell, this is a great way to learn it with help from insiders.”
Ready to rock the help? Contact June Blender (juneb@microsoft.com) or Marco Shaw (marco.shaw@gmail.com).
PSTerminalServices is a PowerShell module that helps you manage Terminal Services (including Remote Desktop connections) sessions and processes. No more legacy applications text parsing!
The module is based on an open source project named Cassia (version 2.0.0.60), a .NET library for accessing the native Windows Terminal Services API.
What you can do with it
The following operations are supported on local and remote computers:
- Enumerating terminal sessions and reporting session information including connection state, user name, client name, client display details, client-reported IP address, and client build number.
- Logging off a session.
- Disconnecting a session.
- Displaying a message box in a session.
- Enumerating all processes or processes for a specified session.
- Killing a process.
Supported Platforms
Cassia has been tested on Windows Server 2008 R2 beta (RTM?), Windows Server 2008, Windows Server 2003, Windows XP, and Windows Server 2000. It should work on Windows Vista as well.
Cassia - Source Files
Cassia source files are included in the module's bin directory (compressed file).
Functions
The following functions are added to the current session when you import the module:
Disconnect-TSSession - Disconnects any attached user from the session.
Get-TSCurrentSession - Provides information about the session in which the current process is running.
Get-TSServers - Enumerates all terminal servers in a given domain.
Get-TSProcess - Gets a list of processes running in a specific session or in all sessions.
Get-TSSession - Lists the sessions on a given terminal server.
Send-TSMessage - Displays a message box in the specified session ID.
Stop-TSProcess - Terminates the process running in a specific session or in all sessions.
Stop-TSSession - Logs the session off, disconnecting any user that might be connected.
Getting help
All functions are decorated with comment-based help so you can use Get-Help against any of the functions just like you would do with any other cmdlet. The module also include a help topic file, about_PSTerminalServices_Module, which you can read by typing the following in your current session:
PS > Get-Help about_PSTerminalServices_Module
Some Code Examples
For more code examples use Get-Help <cmdletName> –Examples.
# Logs off all the active sessions from remote computer 'comp1', no confirmations.
PS> Get-TSSession -ComputerName comp1 -State Active | Stop-TSSession –Force
# Gets all Active sessions from remote computer 'comp1', made from IP addresses that starts with '10'.
PS> Get-TSSession -ComputerName comp1 -Filter {$_.ClientIPAddress -like '10*' -AND $_.ConnectionState -eq 'Active'}
# Displays a message box inside all active sessions of computer name 'comp1'.
PS>$Message = "Important`n, the server is going down for maintenance in 10 minutes. Please save your work and logoff."
PS> Get-TSSession -State Active -ComputerName comp1 | Send-TSMessage -Message $Message
#Gets all processes connected to session ID 0 from remote computer 'comp1'.
PS>Get-TSSession -Id 0 -ComputerName comp1 | Get-TSProcess
Bugs/Suggestions
Bugs related to Cassia can be reported directly to its mailing list: cassia-users@googlegroups.com. Module Bugs/Suggestions/Comments can be reported to the module Discussions page.
Updating an attribute value in Active directory is usually not a big deal. Most of the attributes are single valued and you can easily modify them. However, dealing with multi valued attributes is another game.
With Quest AD cmdlets you don’t have to pull your hair out, there is special syntax for working with multi valued attributes and you use it via the ObjectAttributes parameter. The syntax is as follows (nested hashtable):
Set-QADUser -Identity <Identity> -ObjectAttributes @{AttributeName=@{KeyName=@(‘value1’,’value2’…)}}
AttributeName – The LDAP name of the attribute.
KeyName - The action you want to perform on the attribute value(s). The values
@(‘value1’,’value2’…) – An array of values.
There are four key names we can use to modify multi value attributes:
Append - Adds one or more values to the attribute while preserving any existing entries.
Clear - Removes all values and set the attribute value to null.
Delete - Removes one or more values from the attribute while preserving any other existing entries.
Update - Removes any existing values and then writes one or more new values to the attribute.
Lets take the otherTelephone attribute as an example and get its content.
PS > Get-QADUser -Identity shay -IncludedProperties otherTelephone | Format-List otherTelephone
otherTelephone :
There are no values so let’s add two phone numbers. The ‘Append‘ key name is suitable for that action.
PS > Set-QADUser -Identity shay -ObjectAttributes @{otherTelephone=@{Append=@(‘111-111-1111’,’222-222-2222’)}}
PS > Get-QADUser -Identity shay -IncludedProperties otherTelephone | Format-List otherTelephone
otherTelephone : {111-111-1111, 222-222-2222}
Sometimes we will want to replace all values with new ones:
PS > Set-QADUser –Identity shay -ObjectAttributes @{otherTelephone=@{Update=@(‘333-333-3333’,’444-444-4444’)}}
PS > Get-QADUser –Identity shay -IncludedProperties otherTelephone | Format-List otherTelephone
otherTelephone : {333-333-3333, 444-444-4444}
Now let’s remove one of the numbers:
PS > Set-QADUser –Identity shay -ObjectAttributes @{otherTelephone=@{Delete=@(‘333-333-3333’)}}
PS > Get-QADUser –Identity shay -IncludedProperties otherTelephone | Format-List otherTelephone
otherTelephone : 444-444-444
Finally, to clear all values (set the attribute to null) use the Clear key without any values:
PS > Set-QADUser –Identity shay -ObjectAttributes @{otherTelephone=@{Clear=@()}}
PS > Get-QADUser –Identity shay -IncludedProperties otherTelephone | Format-List otherTelephone
otherTelephone :
The same technique can be used against any multi valued attribute, such as ProxyAddresses (modifying email addresses). How do you know which attributes are multivalued? You can get a list by searching the schema:
PS > Get-QADObject –SizeLimit 0 -LdapFilter "(isSingleValued=FALSE)" –SearchRoot (Get-QADRootDSE).SchemaNamingContext -Type attributeSchema -IncludedProperties LDAPDisplayName | Format-Table LDAPDisplayName
Source: Microsoft Online Services Team Blog
Join Jenna Lyday (Microsoft Online Services PM responsible for e-mail Migration) on Thursday, 1/28/2010 for the third webinar in our migration series. In this webinar, Jenna will demonstrate how to use Windows PowerShell commands to:
- Provision and activate users
- Perform a simple migration from Hosted Exchange to Exchange Online
- Grant a user Full Mailbox Access permissions on another user's mailbox
If you like managing your environment from the command line, or scripting common administrative tasks, don’t miss this week’s webinar.
Date: Thursday, January 28th
Start time: 11: AM Pacific Standard Time (UTC – 8 hrs)
Duration: 1 hour
Click here to register for this webinar.
Click here to view the recording of this webinar. The PowerPoint slides are available here.
Have you ever needed a regular expression to match a numeric range? If so, check Regex_For_Range. This is definitely one of the tools you’d want to add to your Regular Expression toolbox!

One of the most asked question across many PowerShell forums, by Exchange administrators, is how to modify email addresses for mailbox users. The most common used code to add new email address in Exchange 2007 is:
PS > $mbx = Get-Mailbox shay
PS > $mbx.EmailAddresses += “newAddress@domain.com”
PS > Set-Mailbox -Identity $mbx –EmailAddresses $mbx.EmailAddresses
With Windows PowerShell 2.0 and Exchange 2007 (and above, sorry guys no 2003 ) we can use the Update-List cmdlet to add,remove or replace email addresses in a middle of a pipeline.
PS > Get-Mailbox shay | Select-Object -ExpandProperty EmailAddresses | `
Where-Object {$_.PrefixString -eq 'smtp'}
SmtpAddress : shay@domain.com
AddressString : shay@domain.com
ProxyAddressString : SMTP:shay@domain.com
Prefix : SMTP
IsPrimaryAddress : True
PrefixString : SMTP
We see that my mailbox has only one email address. Lets try to add two more addresses and then get the email addresses collection back:
PS > Get-Mailbox shay | `
Update-List -Property EmailAddresses -Add ScriptFanatic@domain.com,ShayL@domain.com | `
Set-Mailbox
PS > Get-Mailbox shay | Select-Object -ExpandProperty EmailAddresses | `
Where-Object {$_.PrefixString -eq 'smtp'}
SmtpAddress : ShayL@domain.com
AddressString : ShayL@domain.com
ProxyAddressString : smtp:ShayL@domain.com
Prefix : SMTP
IsPrimaryAddress : False
PrefixString : smtp
SmtpAddress : ScriptFanatic@domain.com
AddressString : ScriptFanatic@domain.com
ProxyAddressString : smtp:ScriptFanatic@domain.com
Prefix : SMTP
IsPrimaryAddress : False
PrefixString : smtp
SmtpAddress : shay@domain.com
AddressString : shay@domain.com
ProxyAddressString : SMTP:shay@domain.com
Prefix : SMTP
IsPrimaryAddress : True
PrefixString : SMTP
Notice that the primary email address is indicated by the ProxyAddressString property (True) and the ProxyAddressString property which starts the with an uppercased prefix of ‘SMTP:’ . To remove email addresse(s) we use the –Remove parameter:
PS > Get-Mailbox shay | `
Update-List -Property EmailAddresses –Remove ScriptFanatic@domain.com,ShayL@domain.com | `
Set-Mailbox
The Add and Remove parameters can be used together in a pipeline, however we cannot remove the primary address:
PS > Get-Mailbox shay | `
Update-List -Property EmailAddresses -Remove shay@domain.com | Set-Mailbox
Update-List : Cannot remove the primary SMTP address 'shay@domain.com'.
Please promote another valid SMTP address before removing this one.
But we can set a new email address as the primary address (and remove the old one later), just add the ‘SMTP:’ prefix.
PS > Get-Mailbox shay | Update-List -Property EmailAddresses -Add "SMTP:PSFanatic@domain.com" | Set-Mailbox
From the Update-List cmdlet help description:
“This cmdlet works only when the property that is being updated supports the IList interface that Update-List uses. Also, any Set-* cmdlets that accept an update must support the IList interface. The core cmdlets that are installed with Windows PowerShell do not support this interface. To determine whether a cmdlet supports Update-List, see the cmdlet Help topic.”
So, what other properties support the IList interface? With the following command you can get a list of mailbox properties that can be modified with Update-List.
PS > $mbx = Get-Mailbox shay
PS > $mbx.GetType().GetProperties() | `
Where-Object {$_.PropertyType.GetInterface("System.Collections.IList",$true)} | `
Select-Object Name
Name
----
Languages
ProtocolSettings
ResourceCustom
Extensions
AcceptMessagesOnlyFrom
AcceptMessagesOnlyFromDLMembers
AddressListMembership
EmailAddresses
GrantSendOnBehalfTo
PoliciesIncluded
PoliciesExcluded
RejectMessagesFrom
RejectMessagesFromDLMembers
UMDtmfMap
ObjectClass
Finally, there is also a –Replace parameter we can use to replace all existing email addresses with new ones. For more information see the code examples for Update-List.
With PowerShell 2.0 the default Windows Remote Management (WinRM) port numbers has changed from 80/443 (HTTP/HTTPS) to 5985/5986. One reason for changing the ports was a collision with internet servers which used the same ports. These ports are configured when you enable remoting in PowerShell 2.0, typically by using the Enable-PSRemoting cmdlet.
So, if you need a quick reminder about the port numbers WinRM uses for its listeners…
PS > Get-ChildItem WSMan:\localhost\Service\DefaultPorts | Format-Table -AutoSize Name,Value
Name Value
---- -----
HTTP 5985
HTTPS 5986
PS > Get-ChildItem WSMan:\localhost\Client\DefaultPorts | Format-Table -AutoSize Name,Value
Name Value
---- -----
HTTP 5985
HTTPS 5986
Note: To run these commands in Windows Vista, Windows Server 2008, and later versions of Windows, you must start Windows PowerShell with the "Run as administrator" option.
As you probably know PowerShell 2.0 is installed by default on Windows 7 and Windows Server 2008 R2. PowerShell 2.0 shipped with a new feature called Windows PowerShell Integrated Scripting Environment (ISE), A graphical user interface code editor. In PowerShell 2.0 you can launch ISE simply by executing ‘ise’ in the console (built-in Alias) or by clicking on its shortcut(s) in the programs menu.
However, on Windows Server 2008 you won’t be able to find it:

If you open PowerShell and type ‘ise’ you’ll get an error:

So, where exactly is it? ISE is shipped as a Windows Feature. You need to load the Server Manager module and add it with the Add-WindowsFeature cmdlet. Once the feature is added the ‘ise’ Alias will be available and new shortcuts will be placed in the programs folder.

Module authors can use a manifest file for their modules (although this is not required). A manifest file is a .psd1 file that contains a hash table. The keys and values in the hash table describe the contents and attributes of the module, define the prerequisites, and determine how the components are processed. How do you know all the hash table keys? You don’t have to. PowerShell can create the file for you with the New-ModuleManifest cmdlet.
New-ModuleManifest creates a new module manifest (.psd1) file, populates its values, and saves the manifest file in a specified path. You can further edit the file and change the values simply by opening it in your favorite text editor. To verify that your manifest file is valid use the Test-ModuleManifest cmdlet.
OK, now to the gotcha. Here’s a snippet from PSRemoteRegistry manifest file:
# Minimum version of the Windows PowerShell engine required by this module
PowerShellVersion = '2.0'
# Minimum version of the Windows PowerShell host required by this module
PowerShellHostVersion = '2.0'
Modules were introduced in PowerShell 2.0 so it was natural to set the value of ‘PowerShellVersion’ to 2.0. I assumed the same for ‘PowerShellHostVersion’ which proved to be wrong. Why?
When you load the PSRemoteRegistry module in PowerShell everything is working great. PowerShell’s version and Host version are set to 2.0:
PS > $host.Version
Major Minor Build Revision
----- ----- ----- --------
2 0 -1 -1
PS > $PSVersionTable
Name Value
---- -----
CLRVersion 2.0.50727.4927
BuildVersion 6.1.7600.16385
PSVersion 2.0
WSManStackVersion 2.0
PSCompatibleVersions {1.0, 2.0}
SerializationVersion 1.1.0.1
PSRemotingProtocolVersion 2.1
BUT, this is not the case with many PowerShell IDE’s. For example, both of the most popular PowerShell editors, PowerGUI and PowerShell Plus, host versions are not 2.0. These editors use a custom host and the developers can define whatever value they want for the version. If you try to load PSRemoteRegistry in one of these editors you’ll get a similar error to this:
The current PowerShell host is: 'PowerShellPlus Host' (version 1.0.0.0).
The module '...\PSRemoteRegistry.psd1' requires a minimum PowerShell host version of '2.0' to execute.
I would like to thank @jkavanagh58 for reporting the issue!
There are many PowerShell editors out there and you can’t know for sure what host version each one uses, you do though, want your module to load in whatever editor the user uses. To be on the safe side, do not set a value for ‘PowerShellHostVersion’.
UPDATE (01/25/2010), Make sure you read the follow-up post from the PowerShell Team blog.
More Posts
Next page »