Ying Li(MVP) at myITforum.com

PowerShell & System Center
PowerShell Remoting and Sessions

As we all know that Remoting is a big thing in PowerShell V2, you may not know that the key thing to PowerShell Remoting is the “Sessions”. Session is actually not new at all to PowerShell, it exist in V1 and it doesn’t have to be remote!

Let’s see the below cmdlet

get-service i*

It is running locally but it is a (hidden)session

It is equivalent to the below cmdlet

Invoke-command {get-service i*}

To extend that to a remote computer “whatever”, you do this -

Invoke-command –comutername whatever –command {get-service i*}

What happens here is invoke-command establish a session to remote computer “whatever” and then run the cmdlet get-service on the remote computer and then terminate the session.

Not only you could run cmdlet after invoke-command(established a session), you could run a block of scripts as well.

Now you also can do this -

$sessions= new-PSSession –computername whatever1, whatever2

Basically what it does is establish new (remote)sessions on the remote computer whatever1/2 and make them available to you, so you could run your scripts.

Invoke-command –session $sessions {get-eventlog –log security} |sort *computername*

So the point I am trying to make here is that in PowerShell V2, you use invoke-command cmdlet to connect to multiple remote computers and establish “sessions’ to the remote computer and then you run your cmdlets or scripts blocks. Here are some of the cmdlets related to session – New-PSSession; Get-PSSession; Remove-PSSession. You can get the session related cmdlets by using get-command *-PSSession and then you can use get-help to learn the details.

PowerShell (V2) remoting

As we already know that Windows 7 will become generally available on Oct. 22, 2009, and Windows Server 2008 R2 will be broadly available at the same time.

For PowerShell funs, PowerShell V2 will be integrated with Windows 7 and Windows 2008 R2! That is, you don’t have to install (XP/Windows 2003) or enable the feature (Vista/Windows Server 2008). It’s installed and enabled for you!

I have been using PowerShell CTP2/3 and running Windows 7 RC recently, therefore effective using PowerShell V2.

PowerShell V1 has very limited remoting capability. For example, you can’t do get-service on remote computer.  In order to get remote service status, I have to use these codes -

$HealthService = [System.ServiceProcess.ServiceController]::GetServices($Computername) | where{$_.name -eq 'HealthService'}

Now with PowerShell V2, I modified the above codes -

$HealthService = Get-Service -Name "Healthservice" -ComputerName $Computername

It’s much cleaner and Admin friendly! ;)

PowerShell remoting is built on top of Windows Remote Management (WinRM), which is Microsoft’s implementation of WS-Management protocol, which also integrates with WMI.  WinRM enables you to run WMI scripts against remote computers by using standard Internet protocols like HTTP and HTTPS, that means you can manage remote machines over the Internet.

In order to take full advantage of the V2 remoting feature, you do need to install PowerShell and WinRM on the target machines which I know it’s kind stretch in mostly Win2K3/XP Production Environment. But on Vista/Windows server 2008, they are features you could enable, with the upcoming release of Windows 7 and Windows 2008 R2, they are on by default. So it’s about time to get your hands dirty with PowerShell V2/WinRM!

How to setup a Configmgr hierarchies between two AD Forests without trust

Here is a document for setting up Configuration Manager in multiple Active Directory Forest with or without trust. It kind touch on everything but lacking the detailed instruction as to how to set it up!

Let’s say you have a production AD forest which have Configmgr hierarchies in place, you have another AD forest setup for commercial facing websites or whatever reason. The security requirement is NO TRUST between the two forests. How are you going to setup the site to site communication between these two forests?

The forest/domain functional level are Windows server 2003 and above (which meet the minimum requirement – Windows server 2003 domain/forest functional level! Both site has to be primary site according to the doc above! They are both in Mixed mode in our case.

1) Create a standard sender address in both forest in a domain\user format as the computer account won’t work in this scenario;

http://technet.microsoft.com/en-us/library/bb680457.aspx

2) Add the site address account you created above to the Site to Site connection group on the respective site server';

http://technet.microsoft.com/en-us/library/bb632850.aspx

3) Set the Central site (in production forest) as the Parent site for the new site;

http://technet.microsoft.com/en-us/library/bb632349.aspx

4) Last but not least – Manually exchange the public key follow the below link!

http://technet.microsoft.com/en-us/library/bb693690.aspx

That’s all you will have to do to setup site to site communication cross active directory WITHOUT TRUST!

The wait is over – OpsMgr 2007 R2 hits RTM

Yesterday, the OpsMgr 2007 R2 finally hits RTM, you can download the evaluation copy here. The production version will be available until July 1st. But you can install the evaluation copy now and upgrade later.

OpsMgr 2007 SP1 – Creating a rule to monitor logon event

At times some people use service account to logon to machines and it has the potential to lockout the service account and therefore bring down the service which is not acceptable to the business and we would need to create a monitor or rule to monitor this behavior.

We can create a monitor or rule, the process is pretty much the same except the monitor will affect the availability of the business application and the rules do not. Another thing need to pay attention is how you reset the monitor once the state change occurred. So I prefer to use the rule instead:

Go to authoring console, expand Management Pack Objects, right click the rule and select create a new rule, in the next window, expand Alert Generating Rules, expand Event Based, select NT Event Log (Alert), make sure save it in a different Management Pack other than Default Management Pack, see below

image

Type a name for your new rule, set the Rule Category to Alert and set the Rule target to Windows Computer and uncheck Rule is enabled check box. We will do a override later to enable this rule for a targeted group. It is kind counter intuitive but that’s how this things works!

image

Choose Log name to “Security”

image

For the purpose of this blog, I am targeting a Windows 2008 domain and in windows 2008 domain the event ID for successfully logon event is 4624. If you are targeting Windows 2003 domain the event ID is different!

Delete the Event Source row and click Insert, choose the third option – Use parameter name not specified above and type EventDescription in the box and click OK.

image

In the next window, set the Operator to "Contains” and Type the target account in the Value column (xyz\yli here)

image

In the next screen, Type $Data\EventDescription$ in the alert Description Field.

image

Click on the Create button to create the rule.

Next do a overwrite to enable this rule for a pre-defined group which contains all the Windows 2008 domain controllers since all the logon event will be logged on the domain controllers.

image

That is all you need to create a monitor/rule to monitor account logon event. There are some other post outs there but the procedure above did worked for me!

Posted: May 18 2009, 12:55 AM by yli628 | with 1 comment(s)
Filed under:
Antivirus Software Hijacked my Virtual Machines!

It cost me a few hours the other day to do a mini – DR for one of my Hyper-V host! Hopefully this post will save you some trouble in the future.

The trouble starts when I try to build a new VM through VMM 2008, I got the error like below -

The requested operation cannot be performed on a file with a user-mapped section open. (0x800704C8)

Then I thought what about try to create the new VM using Hyper-V manager, I got this error -

VMName’ Microsoft Synthetic Ethernet Port (Instance ID
{7E0DA81A-A7B4-4DFD-869F-37002C36D816}): Failed to Power On with Error 'The specified network resource or device is no longer available.' (0x80070037).

 

I decided to reboot the Hyper-V hosts (this is off business hours and none of my Hyper-V guests are mission critical), and to my unpleasant surprise, four of my six VMs are gone! I would love to see if all the VMs are gone, then it could be the SAN (all the VMs are on a SAN disk) issue. But it puzzles me that just four of them are gone. I checked the SAN disk and it is visible to the OS and I checked all the VHD files for my VM are still on the drive which is encouraging – I could recover the VMs one by one.

But what could cause this problem, I couldn’t create new VM at first and then I lost VMs after reboot the host. I started to call MS support and at the mean time search the internet myself. The search point to Forefront, TrendMicro(which we use), as a matter of fact, all the antivirus software as the culprit.

Now I remember that just recently one of my coworker installed TrendMicro client on the Hyper-V host. So I disabled TrendMicro client on the Hyper-V host, indeed I could create new VMs after that and I was able to restore the “lost” VMs. Later MS tech call me back and confirmed that the antivirus (TrendMicro in our case) software can corrupt the VM configuration files and therefore lost the VMs after rebooting the host. It can also prevent us to create new VMs.

http://support.microsoft.com/default.aspx?scid=kb;EN-US;961804

Lesson learned, we need to create exclusion for our Antivirus software for all the Hyper-V host following the above KB!

PowerShell 1.0 is now available as an optional update

Great News! On Tuesday (3/24/09),Microsoft published PowerShell 1.0 on Windows Update!

PowerShell 1.0 through MU is only offered:

· As an optional update

· If you don’t have any other version of PowerShell installed (including V2 CTPs) on your machine

· .NET 2.0 is installed on the machine

· OS is one of: XP-SP3, W2K3-SP2, Vista-RTM, Vista-SP1

With PowerShell 1.0 on Windows update, it will now reach a  broader audience, (3.5 million downloads so far). This will help the user community to get ready for the rich set of features of PowerShell V 2.0 on the upcoming release of Windows 7 OS. Also it is safe to assume that the PowerShell 2.0 will be pushed through WU/MU/WSUS for enterprise deployment.

Cheers!

PowerShell Script to Create Multiple Exchange Mailbox and Set Primary SMTP Addresses

I am working on a request to create ~800 user's Exchange 2007 SP1 mailboxes from an excel file.

The file with the following headers filled with user's information.

Name, FirstName, MI, LastName, Email, OU

The Alias will be in firstname.mi.lastname if there is a MI or otherwise in firstname.lastname format.

I come up the following script:

$Password=Read-Host "Enter Password" -AsSecureString

Import-CSV c:\users.csv | foreach {new-ma
ilbox -firstname $_.firstname -initials $_.MI -Lastname $_.lastname -alias ($_.f
irstname + "." + $_.MI + "." + $_.lastname) -name $_.name -userPrincipalName $_.
email -database "server1\storage group" -org $_.OU -Password $Password -Reset
PasswordOnNextLogon $True}

If the MI column is blank, just removed $_.MI part from the script because Exchange doesn't understand the firstname..lastname!

I thought that would be it, right? Not quite!

It turns out we have a default policy in place which will automatically change the email address format to first initial + lastname (yli instead ying.li)

So I modified the script as follows:

Import-CSV c:\users.csv | foreach {new-ma
ilbox -firstname $_.firstname -initials $_.MI -Lastname $_.lastname -alias ($_.f
irstname + "." + $_.MI + "." + $_.lastname) -name $_.name -userPrincipalName $_.
email -database "server1\storage group" -org $_.OU -Password $Password -Reset
PasswordOnNextLogon $True}|set-mailbox -emailaddresspolicyenabled $false

which will check off the "Automatically update e-mail addresses based on e-mail address policy" box in user's mailbox property (email address page), this will prevent the newly created user from inherit the default policy.

I checked the results - the email address already re-formated to yli instead ying.li before the check off policy taking place!

I end up have to run the below script against the excel sheet to reset the user's primary smtp address to ying.li@whatever.com

Import-CSV c:\users.csv | foreach {$user
= get-mailbox -id ($_.firstname + "." + $_.MI + "." + $_.lastname);$user.emailad
dresses.add($_.email);set-mailbox -instance $user -primarysmtpaddress $_.email}

Now it is all happy!

PowerShell to help Web Site Launch – Multiple Host Headers on Multiple Web Servers

Quite often I receive requests to launch a website with multiple domain names and they will need to work with or with out www such as whatever.com and www.whatever.com. The site need to be launched on NLB cluster nodes. I got the contents from developers and copy them over to the production web servers and make necessary configurations – routine stuff.

But if the request is multiple domain names to point to the same site, the task is daunting! 30-50 domains, I have to create DNS zones one by one. Our external DNS is hosted on Windows 2000 and I am hesitate to install PowerShell on it! So for now, I create the dns zones manually (expect to upgrade the DNS server to Windows 2008 soon)!

How about Host Headers, 30 domains multiple by 2 for the www and set them up on two nodes NLB cluster, the picture is not pretty if you do them manually!

Let’s say I got the domain names from business in below format:

whatever.com
whatever1.com
whatever2.com
whatever3.com
whatever4.com

 

All point to whatever.com and people on the internet should hit them with or without www. Here is my solution:

Save the above domain name in DNSZones.txt

run the little script -

foreach ($zone in (gc .\DNSZones.txt))
{$www = "www." +$Zone;add-content ".\DNSZones.txt" $www}

Now the DNSZones.txt looks like this:

whatever.com
whatever1.com
whatever2.com
whatever3.com
whatever4.com
www.whatever.com
www.whatever1.com
www.whatever2.com
www.whatever3.com
www.whatever4.com

Next run the below script -

New-Item "C:\Users\yl\Documents\PS\Hostheader.txt" -Type file
foreach ($zone in (gc .\DNSZones.txt))
{$IPBinding = "192.168.1.23:80:" +$Zone;add-content ".\Hostheader.txt" $IPBinding}

Now the file will be look like below – 192.168.30.23 is the NLB cluster VIP

192.168.30.23:80:whatever.com
192.168.30.23:80:whatever1.com
192.168.30.23:80:whatever2.com
192.168.30.23:80:whatever3.com
192.168.30.23:80:whatever4.com
192.168.30.23:80:www.whatever.com
192.168.30.23:80:www.whatever1.com
192.168.30.23:80:www.whatever2.com
192.168.30.23:80:www.whatever3.com
192.168.30.23:80:www.whatever4.com

Why I go through all these trouble and have a file format like that? That’s the Metabase.xml serverbinding format:

I have direct metabase edit enabled on my web servers, I make a BACKUP copy of the metabase.xml file and then open the live one in notepad and search for whatever.com and underneath that, I look for ServerBindings=" “ and paste the above text file inside the quote and save the file. Open the website property and verify all the host headers are in place! Repeat the same thing for the other NLB nodes. Isn’t that cool!

Wait, I am not out of the woods yet, with that many domain names, everyone involved could easily make a mistake somewhere and we don’t want the business or customer find that out first – how you verify all the domain names resolve and point to the same site? Again, PowerShell!

Remember the DNSZones.txt? I save the below script as CheckWebs.ps1 and run it.

foreach ($domain in gc .\DomainZones.txt)
{

$ie = new-object -comobject "InternetExplorer.Application"

#$ie.visible = $true

$ie.navigate("http://" + $domain + ".com")

}

I could easily find out which domain or site is not working, so I can double check!

Only then I feel a little bit love for my job. Most the time, I hate it! :)

ConfigMgr – Create a collection based on 64 bit Add/Remove Programs

Here is a query to create a collection based on 64 bit add/remove program

select SYS.ResourceID,SYS.ResourceType,SYS.Name,SYS.SMSUniqueIdentifier,SYS.ResourceDomainORWorkgroup,SYS.Client from SMS_R_System as sys inner join  SMS_G_System_ADD_REMOVE_PROGRAMS_64 on  SMS_G_System_ADD_REMOVE_PROGRAMS_64.ResourceID = sys.ResourceId where  SMS_G_System_ADD_REMOVE_PROGRAMS_64.DisplayName like "%Microsoft Windows Server Update Services 3.0 SP1" order by sys.Name

Upgrade ConfigMgr 2007 from Evaluation version to Production Version

Searching on the net, this is a frequently asked question and it was a great concern to me too!

I used Evaluation copy of the media to set up our ConfigMgr 2007 environment and the other day, when I try to expand the Collections or Software Updates, I got an error “ you do not have security right to perform this operation”. All the users I created under Security Rights include myself are gone! Before I go panic, I remember that it’s about time for the Evaluation copy to expire! Rule number one - Think Simple!

But as we know for ConfigMgr there is no way we can upgrade to production version from evaluation copy by just update the product key somewhere. We have to get the media with product key and re-run the install which concerns me – can I keep the settings?

The answer is Yes, We Can! We could just use the production media and run the setup and it will discover the primary site and do an upgrade! It INDEED keep all the settings except I do lose the users which I created under Security Rights! Which is not really a big deal!

Another thing puzzles me is that why Microsoft don’t give us an “Evaluation copy expired” error message and instead give us the above error which can get people lost sometime!

Windows 7 know how

When I try to ping a brand new install of Windows 7 (beta). I got the “Request Timed out” error and when I try to use PowerShell to restart the Windows 7 box remotely, I got the below error:

Restart-Computer -computername neptune
Restart-Computer : The RPC server is unavailable. (Exception from HRESULT: 0x800706BA)
At line:1 char:17
+ Restart-Computer <<<<  -computername neptune
    + CategoryInfo          : InvalidOperation: (:) [Restart-Computer], COMException
    + FullyQualifiedErrorId : RestartComputerException,Microsoft.PowerShell.Commands.RestartComputerCommand

How to fix this?

On the Windows 7 box, I go to Control Panel – Windows Firewall, in "Allow programs to communicate through Windows Firewall” I enabled “File and Printer Sharing” and “Windows Management Instrumentation(WMI)”, I am now able to ping the Windows 7 box successfully. When I try to restart-computer again, I get a new error:

Restart-Computer -computername neptune
Restart-Computer : This command cannot be executed on target computer('neptune') due to following error: The system shu
tdown cannot be initiated because there are other users logged on to the computer.
At line:1 char:17
+ Restart-Computer <<<<  -computername neptune
    + CategoryInfo          : InvalidOperation: (neptune:String) [Restart-Computer], InvalidOperationException
    + FullyQualifiedErrorId : InvalidOperationException,Microsoft.PowerShell.Commands.RestartComputerCommand

What if I insist to reboot the Windows 7 box, Yes I can!

Restart-Computer –computername neptune -force

PowerShell Provider for Remote Desktop Services (Terminal Services)

In case you haven't noticed, Microsoft renamed Terminal Services as Remote Desktop Services from Windows 2008 R2 onwards! It does caught me by surprise to get used to the new NAME!

But I am happy to report that the beta release of Windows server 2008 R2 supports managing Remote Desktop Service(Terminal Services) using PowerShell!

The PowerShell provider comes with the Remote Desktop Services role, once you have the RDS role enabled, the PowerShell provider lets you to configure and manage all the Remote Desktop Services related tasks.

Microsoft Remote Desktop Service Program Manager Shanmugam Kulandaivel has a detailed article here to help you get started. I do want to point out that you will need to have PowerShell installed on the managed servers in order to use RDS PowerShell provider!

This is one step further toward the ultimate goal - PowerShell everywhere, ie all the windows management interface and the web management interface will be build on PowerShell. Stay tuned!

PowerShell Script to create new registry key value on remote computers

In this post, I explore the ways to get remote registry key property. Here is a PowerShell script to create a new registry key value in remote registry.

$colComputers = gc c:\myworkspace\computerlist.txt

foreach ($strComputer in $colComputers)

{

#Open remote registry

$reg = [Microsoft.Win32.RegistryKey]::OpenRemoteBaseKey('LocalMachine', $strComputer)

#Open the targeted remote registry key/subkey for read and write ($True)

$regKey= $reg.OpenSubKey("SOFTWARE\\Whatever\\General",$True)

#Create a new (string)value –“Override System Verification” and assign “Yes”  to it

$regKey.Setvalue('Override System Verification', 'Yes', 'String')

PowerShell Script to Shutdown Multiple Remote Computers

In my previous post, I described the restart-computer cmdlet. There is also a sister cmdlet. Yes, you guessed it right: Shutdown-computer

Shutdown-computer –computername (gc c:\temp\serverlist.txt) –force –throttlelimit 10

You could force the immediate shutdown of multiple remote computers and shutdown 10 at a time!

PowerShell Script to Restart multiple Remote Computers

Right before Christmas, PowerShell team released Windows PowerShell V2 Community Technology Preview 3 (CTP3). There is a new cmdlets caught my eye, see below

gc c:\Temp\ServerList.txt |%{Restart-computer –computername $_ –force}

It gets a list of computers and force the immediate restart!

 

It’s very handy and also can be very dangerous, you could potentially reboot every single computer in your company!

Get-QADComuter|%{Restart-Computer –computername $_ –force –throtllelimit 1-}

PowerShell script to get remote registry key property

The first half of the below script is a modified version of my previous post, it just translate the BITS version to the popular format we know and remember. The second part of the script is to use a get-remoteregistrykeyproperty.ps1 written by Lee Holmes in his Windows PowerShell Cookbook. I believe that's so far the cleanest way to get key value from remote registry. Of course the hard work was taken care by Lee!

$erroractionpreference = "SilentlyContinue"

$a = New-Object -comobject Excel.Application
$a.visible = $True

$b = $a.Workbooks.Add()
$c = $b.Worksheets.Item(1)

$c.Cells.Item(1,1) = "Machine Name"
$c.Cells.Item(1,2) = "Ping Status"
$c.Cells.Item(1,3) = "Operating System"
$c.Cells.Item(1,4) = "Version"
$c.Cells.Item(1,5) = "Disk TimeOutValue"

$c.Cells.Item(1,6) = "Report Time Stamp"

$d = $c.UsedRange
$d.Interior.ColorIndex = 19
$d.Font.ColorIndex = 11
$d.Font.Bold = $True

$intRow = 2

$regPath= "HKLM:\System\CurrentControlSet\Services\Disk"

$colComputers = gc c:\myworkspace\ServerList.txt

foreach ($strComputer in $colComputers)
{
$c.Cells.Item($intRow,1) = $strComputer.ToUpper()

Function PingComputer
{
$ping = new-object System.Net.NetworkInformation.Ping
$Reply = $ping.send($strComputer)
if($Reply.status –eq “Success”)
{
$c.Cells.Item($intRow, 2) = “Online”

Function GetFileInfo
{
$OS = (gwmi -class Win32_OperatingSystem -computer $strComputer).Caption
$c.Cells.Item($intRow,3) = $OS

$OSVersion = (gwmi -class Win32_OperatingSystem -computer $strComputer).version
if ($OSVersion -le 5.1)
{
$Path = "\\"+ $strComputer + "\C$\Winnt\System32\qmgr.dll"
}
else
{
$Path = "\\"+ $strComputer + "\C$\Windows\System32\qmgr.dll"
}

$File = get-item $Path
$BitVer = $File.VersionInfo.Productversion
$BitVer = $BitVer.split('.')[0]+'.'+ $BitVer.split('.')[1]

Switch($BitVer)
{
7.0 {$BitVer = "BITS 3.0"}
6.7 {$BitVer = "BITS 2.5"}
6.6 {$BitVer = "BITS 2.0"}
6.5 {$BitVer = "BITS 1.5"}
}

$c.Cells.Item($intRow,4) = $BitVer
}

GetFileInfo

$DTV = .\get-remoteregistrykeyproperty.ps1 $strcomputer $regpath "TimeoutValue"

$c.Cells.Item($intRow,5) = "{0:X}" -f $DTV.TimeOutValue
}
else
{
$c.Cells.Item($intRow, 2).Interior.ColorIndex = 3
$c.Cells.Item($intRow, 2) = "Offline"
}
}
PingComputer

$c.Cells.Item($intRow,6) = Get-date

$ping.status = $null
$intRow = $intRow + 1
}

$d.EntireColumn.AutoFit()

You can modify the regpath and key value to suite your need. Also Below is the full script copied from Lee Holmes book(or web link):

##############################################################################
##
## Get-RemoteRegistryKeyProperty.ps1
##
## Get the value of a remote registry key property
##
## ie:
##
##  PS >$registryPath =
##       "HKLM:\software\Microsoft\PowerShell\1\ShellIds\Microsoft.PowerShell"
##  PS >Get-RemoteRegistryKeyProperty LEE-DESK $registryPath "ExecutionPolicy"
##
##############################################################################

param(
  $computer = $(throw "Please specify a computer name."),
  $path = $(throw "Please specify a registry path"),
  $property = "*"
  )

## Validate and extract out the registry key
if($path -match "^HKLM:\\(.*)")
{
    $baseKey = [Microsoft.Win32.RegistryKey]::OpenRemoteBaseKey(
        "LocalMachine", $computer)
}
elseif($path -match "^HKCU:\\(.*)")
{
    $baseKey = [Microsoft.Win32.RegistryKey]::OpenRemoteBaseKey(
        "CurrentUser", $computer)
}
else
{
    Write-Error ("Please specify a fully-qualified registry path " +
        "(i.e.: HKLM:\Software) of the registry key to open.")
    return
}

## Open the key
$key = $baseKey.OpenSubKey($matches[1])
$returnObject = New-Object PsObject

## Go through each of the properties in the key
foreach($keyProperty in $key.GetValueNames())
{
    ## If the property matches the search term, add it as a
    ## property to the output
    if($keyProperty -like $property)
    {
        $returnObject |
            Add-Member NoteProperty $keyProperty $key.GetValue($keyProperty)
    }
}

## Return the resulting object
$returnObject

## Close the key and base keys
$key.Close()
$baseKey.Close()

PowerShell script to create AD accounts (II)

In my previous post, I blogged about how to create AD accounts using PowerShell and Quest PowerShell commands for AD. Below is a similar script with some modifications.

What happens you get a csv file which doesn't have a name column but have lastname, firstname etc. You want to create the AD accounts with certain format such as test_lastname. We just need some concatenations.

import-csv Users1.csv |%{New-QADUser -ParentContainer 'OU=abc, DC=xyz, Dc=com' -name ($_.lastname+ ',' +$_.firstname) -samAccountName('test_' + $_.lastname)}

PowerShell one liner to query only servers in AD

Let's say you want to query all the servers in AD, here is a PowerShell one liner to do it, you need to have Quest PowerShell commands for Active Directory installed of course.

Get-QADComputer -sizelimit 0 -OSName '*server*'|export-csv Servers.csv

You could limit the search to a particular OU by using the -searchroot switch.

PowerShell script to find all the .admin users in AD

Let's say every user (in IT) has two accounts - one is their regular user account and the other is their admin account. It could be in the form of xyz.admin(or any other format). How you go about searching your active directory and find all the .admin accounts?

it couldn't be easier than this:

Get-QADUser -ldapFilter '(SamAccountName=*.admin)'|export-csv admins.csv

Of course, you need to have PowerShell Commands for Active Directory from Quest installed first!

PowerShell script to delete sub folders old than certain days

In my previous Blog, I discussed how to use PowerShell script to delete files old than certain days. At the time I was focused on the files (log files in particular). Recently there is a need to do the similar thing for folders like if you have Backup folder contain sub backup folders created on different date. Here is a modified script to get the job done.

Function RemoveOldFile
{
param ($strComputer = $(Read-Host "Please Enter The Server Name")),
       ($Dir = $(Read-host "Please Enter The Directory Path"))
       ($Days = $(Read-Host "How Many Days?"))

$TargetFolder = "\\" + $strComputer + "\" + $Dir
if (Test-Path $TargetFolder)
{

#Warn you the targeted folder, so you can double check
  Write-host "The Targeted Folder is:" $TargetFolder -foregroundcolor "Red"
  Write-Host `a `a `a `a `a
  Write-Host "If This Is Not The Intended Target, Press 'Ctrl + C' To Exit" -foregroundcolor "Yellow"
  Start-sleep -s 15

  $Now = Get-Date

# Notice the minus sign before $days
  $LastWrite = $Now.AddDays(-$days)
  Get-ChildItem $Targetfolder |Where {$_.LastWriteTime -le "$LastWrite"}|remove-item -recurse
}
Else
{Write-Host "The Folder $TargetFolder Does Not Exist!"}
}
RemoveOldFile

Enjoy!

PowerShell script to identify what vm machines are on a particular LUN

We have a VMWare infrastructure which connects to the SAN. Every now and then we will get "running out disk space" error for a particular LUN. What we need to do is to identify what other machines are on the same LUN, then we can address the disk space issue accordingly. Here is a PowerShell one liner to accomplish this and of course you need to have VMWare VI ToolKit installed.

Get-ESX # to connect to the target ESX box

Get-vm -datastore "lunxy"

PowerShell script to create AD accounts

If you keep getting request to create multiple (service) accounts in AD, you got to think what PowerShell can do for this task. Before Microsoft releases it's own AD Cmdlets, we will have to use PowerShell commands for Active Directory from quest. You can download the latest version Here.

After you get it installed, you can start a regular PowerShell session and type:

Add-PSSnapIn Quest.ActiveRoles.ADManagement

This will extend the PowerShell for AD

First we save the plaintext password as a AsSecureString

PS C:\Users\yl.admin\Documents\PS> $pw = read-host "Enter password" -AsSecureString
Enter password: ********

Then connect to the targeted domain

PS C:\Users\yl.admin\Documents\PS> Connect-QADService -service 'xyzdcs01.xyz-stage.com' -ConnectionAccount 'xyz-stage\administrator' -ConnectionPassword $pw

Once you establish the connection to AD, you can import the csv file which has the below format:

Name            Description
Svc_SP_IntrAP        Intranet content web application pool
Svc_SP_IntrSSPAP    Intranet farm shared services provider application pool

PS C:\Users\yl.admin\Documents\PS> import-csv C:\myworkspace\user.csv |%{new-qadUser -ParentContainer 'OU=Service Ac
ts,DC=xyz-stage,DC=com' -name $_.name -samAccountName $_.name -description $_.Description}

You will see the list of accounts created after you run the above script.

PowerShell script to push BITS 2.5 to remote computers

After we got a list of computers need BITS 2.5 discussed in my previous Post. We could use the below script to push BITS 2.5 to them

$colComputers = gc c:\users\yl.admin\pstools\ComputerList.txt
Foreach ($strComputer in $colComputers)

{.\psexec.exe -c \\$strComputer \\server\share\WindowsXP-KB923845-x86-ENU.exe /quiet /norestart}

You will see something like this which is perfectly fine and it just means reboot is required and pending!

WindowsXP-KB923845-x86-ENU.exe exited on $strcomputer with error code 3010.

PowerShell script to check BITS version

BITS 2.5 is a required component by ConfigMgr 2007. The ccmsetup will automatically install BITS 2.5 if the client doesn't have it but there is a little catch - it will reboot the machine! I have been trying to find a way to suppress the reboot and so far without success.

It seem the only way to control the reboot is to pre-install BITS 2.5. Before I do that, here is a PowerShell script to query BITS version on multiple remote computers.

$erroractionpreference = "SilentlyContinue"

$a = New-Object -comobject Excel.Application
$a.visible = $True

$b = $a.Workbooks.Add()
$c = $b.Worksheets.Item(1)

$c.Cells.Item(1,1) = "Machine Name"
$c.Cells.Item(1,2) = "Ping Status"
$c.Cells.Item(1,3) = "File Name"
$c.Cells.Item(1,4) = "Version"
$c.Cells.Item(1,5) = "Report Time Stamp"

$d = $c.UsedRange
$d.Interior.ColorIndex = 19
$d.Font.ColorIndex = 11
$d.Font.Bold = $True

$intRow = 2

$colComputers = gc c:\myworkspace\MachineList.txt

foreach ($strComputer in $colComputers)
{
$c.Cells.Item($intRow,1) = $strComputer.ToUpper()

Function PingComputer
{
$ping = new-object System.Net.NetworkInformation.Ping
$Reply = $ping.send($strComputer)
if($Reply.status –eq “Success”)
{
$c.Cells.Item($intRow, 2) = “Online”

Function GetFileInfo
{
$OSVersion = (gwmi -class Win32_OperatingSystem -computer $strComputer).version
if ($OSVersion -le 5.1)
{
$Path = "\\"+ $strComputer + "\C$\Winnt\System32\qmgr.dll"
}
else
{
$Path = "\\"+ $strComputer + "\C$\Windows\System32\qmgr.dll"
}

$File = get-item $Path

$c.Cells.Item($intRow,3) = $File.Name
$c.Cells.Item($intRow,4) = $File.VersionInfo.Productversion
}

GetFileInfo

}
else
{
$c.Cells.Item($intRow, 2).Interior.ColorIndex = 3
$c.Cells.Item($intRow, 2) = "Offline"
}
}
PingComputer

$c.Cells.Item($intRow,5) = Get-date

$ping.status = $null
$intRow = $intRow + 1
}

$d.EntireColumn.AutoFit()

Setup ConfigMgr SP1 on Windows Server 2008

In my previous post, I described how to get your ConfigMgr SP1 environment up and running in no time. Now here is a update version for how to set up ConfigMgr SP1 environment in Windows Server 2008. Enjoy!

Download the doc Here

How to join a client to a domain behind a NAT environment

We have a development domain setup inside (VMWare) Labmanager which is "isolated" from outside. Each machine has it's private IP address such as 10.10.10.x and also has an "external" IP Address such as 172.16.48.x. There is a need to add machine external to labmanager which has 172.16.48.* address to this dev domain.

When I try to join a test XP machine to the domain I receive the following message:

Note: This information is intended for a network administrator. If you are not your network's administrator, notify the administrator that you received this information, which has been recorded in the file C:\WINDOWS\debug\dcdiag.txt.

The following error occurred when DNS was queried for the service location (SRV) resource record used to locate a domain controller for domain xyz-dev.com:

The error was: "This operation returned because the timeout period expired."
(error code 0x000005B4 ERROR_TIMEOUT)

The query was for the SRV record for _ldap._tcp.dc._msdcs.xyz-dev.com

The DNS servers used by this computer for name resolution are not responding. This computer is configured to use DNS servers with the following IP addresses:

172.16.48.10

Verify that this computer is connected to the network, that these are the correct DNS server IP addresses, and that at least one of the DNS servers is running.

For more information on how to correct this problem, click Help.

172.16.48.10 is the "external" IP address for the domain controller/DNS server in dev domain

In order to correct this error, I added the following to the host file on the XP test machine

172.16.48.10             xyz-dev.com

The I see some progress and got a different error:

DNS was successfully queried for the service location (SRV) resource record used to locate a domain controller for domain xyz-dev.com:

The query was for the SRV record for _ldap._tcp.dc._msdcs.xyz-dev.com

The following domain controllers were identified by the query:

xyzdcd01.xyz-dev.com

Common causes of this error include:

- Host (A) records that map the name of the domain controller to its IP addresses are missing or contain incorrect addresses.

- Domain controllers registered in DNS are not connected to the network or are not running.

For information about correcting this problem, click Help.

Even after I added the below entry in the host file - I still get the same error messag:

172.16.48.10                xyzdcd01.xyz-dev.com

After give it some thought. I believe the problem is because the test machine can resolve to xyz-dev.com through the first entry in the host file

172.16.48.10      xyz-dev.com

it queries the SRV record and got the domain controller name which is xyzdcd01.xyz-dev.com - all happy so far!

but the IP address the test machine got for the DC is not 172.16.48.10 but rather the internal IP address of the DC/DNS box which happens to be 10.10.10.10 which the test box has no way to connect to and the second entry in host file

172.16.48.10        xyzdcd01.xyz-dev.com doesn't help at all!

I tried to create a new Host(A) record for the DC let the xyzdcd01.xyz-dev.com has two A record one is point to internal IP address 10.10.10.10 and the other point to external IP address 172.16.48.10 and I can then add the test xp machine to the domain. But before I got too excited about this - I realizes and noticed that I can't do that, the DNS server automatically delete the "external" A record for the DC after a while!

Then I went back to read the above error message and focus my attention on:

_ldap._tcp.dc._msdcs.xyz-dev.com

I then go to the DNS server and modify the above pointer to the external IP address 172.16.48.10 (it had the internal IP address by default)!

Now the "external" machines can join the dev domain and the machine inside the labmanagers can still join the dev domain because they each has an external IP address and they can go out (they are setup to use the external getaway) to join the domain.

After that I created a secondary DNS zone on my "external" production DNS server which now hold the zone information for xyz-dev, so I don't have to add the xyz-dev.com host file entry. All I need to do is to let the client using the external IP address of the dev DNS server as it's preferred DNS server IP address if I need to add that client to the dev domain.

I spent quite some time on this and figure to share them but keep in mind, this may not be an officially supported scenario and may have unintended consequences!

PowerShell script to remove virtual machine from VMWare Infrastructure

Forget about the trip to Las Vegas I mentioned before, I started to like VMWare VI Tookkit the more I use it!

You just need to cultivate a habit, every time if you need to repetitively doing something, you should ask yourself if you can do it with PowerShll. More likely than not, the answer is YES, WE CAN!

Like I have a bunch of cloned vm box acting as a backup to our MOSS staging environment. We are tight on resource and so we decided to delete all the clones. Instead right click one by one, you can use the below script. Thanks Hal's comment to my previous post, it's now much simpler!

get-vm clone*|remove-vm -deletedfromdisk

But I do notice that after I remove vm this way, I got something like

clone-xyz(orphaned), you may have to add remove-inventory but I wasn't able to test this part!

Similarly you could do:

get-vm xyzmoss* |shutdown-vmguest

and

get-vm xyzmoss* |start-vm

Posted: Aug 19 2008, 08:57 PM by yli628 | with 3 comment(s)
Filed under:
PowerShell Script to Take Snapshot on Multiple VM Machines

In my previous Blog, I introduced some basics about VMWare Infrastructure Toolkit. Now let's put it into action!

Let's say you have a test MOSS or SMS virtual environment, you have a couple of servers and you configured everything and test everything. Before you make the next big change, you may want to take a snapshot of your machines so you can have some to fall back on if something goes bad!

It couldn't easier with VI Toolkit!

$Now = Get-Date

#get all your moss servers
$VMs = get-vm |where{$_.name -like "xyzmoss*"}
foreach ($vm in $VMs)

#Take snapshots for each VM Box
{new-snapshot -vm $vm -name $Now -confirm}

Posted: Aug 18 2008, 11:26 PM by yli628 | with 4 comment(s)
Filed under:
PowerShell Script to refresh GPO remotely on multiple computers

Here is a KB article explains how to refresh the Group Policy Settings on remote computers. Basiclly you need to download PsTools from SysInternals and run something like this:

For Windows XP Computers:
Psexec.exe -@ComputerList.txt Gpupdate.exe /Target:User /force
Psexec.exe -@ComputerList.txt Gpupdate.exe /Target:Computer /force

Where you have the computer names in the ComputerList.txt file. I made a little effort to translate that into PowerShell

$colComputers = gc c:\users\yl.admin\pstools\ComputerList.txt

Foreach ($strComputer in $colComputers)

{.\psexec.exe \\$strComputer gpupdate.exe /target:computer /force}

You can change the target to user at you wish.

Posted: Aug 14 2008, 03:34 PM by yli628 | with 1 comment(s)
Filed under:
More Posts Next page »