Archive

Posts Tagged ‘powershell’

Powershell: Create new mailbox database

After installing MS Exchange 2010 in my test lab, I want to create new mailbox database in my server. While I can do it with GUI, I am more interested in exploring the powershell way…

The exchange management shell is having very large set of cmdlets to manage exchange. In fact the GUI also is a wrapper on top of Powershell commands. So learning these commands and using them in daily operations is really useful and you can go into granular details.

New-MailboxDatabase is the cmdlet that accomplished my task here.

New-MailboxDatabase -EdbFilePath C:\Database\MailboxDB1.edb -Server TIBDC1 -Name MailDB1

Here I am creating a new mailbox database with name MailboxDB1 and placing the EDB file C:\Database folder with MailboxDB1.EDB file name. You might ask what happens to log files and where they will be saved. By default logfiles go with EDB file unless the path is specified with -LogFolderPath parameter. The -Server parameter specifies the server name where this database is going to be created.

You won’t see the creation of EDB file or logfiles in the given folder unless you mount it. So we need to use Mount-Database cmdlet to mount the newly created database. You can use the below command for that purpose.

Get-MailboxDatabase -Identity MailDB1 | Mount-Database

Hope this helps… and you will see more exchange stuff in my upcoming posts.

 

Powershell: How to get Groups list of a computer account

One of my old friend/colleague called me to day for a small help. He is looking for script to get the list of active directory groups that a computer account is member of. Since this is a very basic requirement every System administrator will get, I wanted to post it in my blog.

So, the code described in this post uses Quest Active Directory powershell cmdlets. I can code using the dotnet objects or built-in activedirectory module in windows 7/2008 as well but since I wanted to make it more generic, I opted for Quest cmdlets. Another advantage is that even newbies can query AD with these tools efficiently.

Since I am using Quest AD cmdlets, you should down load them from http://www.quest.com/powershell/activeroles-server.aspx and installed it on your computer. After installation, copy the below code into a file called Get-ComputerGroups.ps1 and run it from Quest AD shell(you can launch this from program files), as shown below.

Get-ComputerGroups.ps1

[cmdletbinding()]
param(
[parameter(mandatory=$true)]
$ComputerName
)            

$Groups = (Get-QADComputer -Id $ComputerName).Memberof            

$Groups | % {
$_.split(",")[0].Split("=")[1]
}

Usage:

[PS] C:\temp\Get-ComputerGroups.p1 -ComputerName MyPC1

Here -ComputerName parameter is mandatory.

Similarly, if you want to provide the computer names from text file and get the active directory group names of all of them, then use the below code.

Get-ComputerGroups.ps1

[cmdletbinding()]
param(
[parameter(mandatory=$true)]
$FilePath
)            

$Computers = Get-Content $FilePath
foreach ($ComputerName in $Computers) {
    write-host "$ComputerName is memberOf following Groups"
    $Groups = (Get-QADComputer -Id $ComputerName).Memberof
    $Groups | % {
    $_.split(",")[0].Split("=")[1]
}            

}

Usage:

[PS] C:\> Get-ComputerGroups.ps1 -FilePath c:\temp\Computersfile.txt

If you want to redirect the output to a text file, just try the below command.

[PS] C:\> Get-ComputerGroups.ps1 -FilePath c:\temp\Computersfile.txt | Out-File c:\temp\output.txt

The output will be written to output.txt file.

Feel free to comment here if you have any doubts.

 

Powershell: Change/Set Power plans in Windows 7/Windows 2008 R2

February 28, 2012 1 comment

Are you looking for a way to change power plan on local or remote computer? You are at the right place. The script discussed in this article will help you in changing the power plans in PowerShell way. MS built-in tool(powercfg.exe) is available that can also help you to do this job. But I am not using that tool in my script by building a wrapper around it. I am simply relying on WMI class to change the power plan. I recommend WMI way because using executables inside script is not a good practice and it should be our last resort when it is not possible through WMI or dotnet class or some API.

The Win32_Powerplan WMI class will return list of power plans available in the computer. This list includes built-in power plans like”Power Saver”, “Balanced” and “high performance” plus any custom power plans that user has created. Each returned power plan a again  a object which will have a method called Activate() to activate the current power plan. This power plan object also contains a proper called IsActive which will be set to $true if is the active power plan that system is using currently.

The code follows…

Set-PowerPlan.ps1

[cmdletbinding()]                        

param (
[parameter(ValueFromPipeline=$true,ValueFromPipelineByPropertyName=$true)]
[string[]]$ComputerName = $env:computername,                        

[ValidateNotNullOrEmpty()]
[parameter(Mandatory=$true)]
[ValidateSet("Power Saver", "Balanced", "High Performance")]
[string]$PowerPlan                        

)                        

begin{}                        

Process {
foreach ($Computer in $ComputerName) {
 if(Test-Connection -ComputerName $Computer -Count 1 -ea 0) {
  Write-Verbose "$Computer is online"
  $PreviousPowerPlan = Get-WmiObject -Class Win32_Powerplan -Namespace root\CIMV2\Power -ComputerName $Computer | ? {$_.IsActive -eq $true}
  $CurrentPowerPlan  = Get-WmiObject -Class Win32_Powerplan -Namespace root\CIMV2\Power -ComputerName $Computer | ? {$_.ElementName -eq $PowerPlan}
  $CurrentPowerPlan.Activate()
  $OutputObj  = New-Object -Type PSObject
  $OutputObj | Add-Member -MemberType NoteProperty -Name ComputerName -Value $Computer.ToUpper()
  $OutputObj | Add-Member -MemberType NoteProperty -Name PreviousPlan -Value $PreviousPowerPlan.ElementName
  $OutputObj | Add-Member -MemberType NoteProperty -Name CurrentPlan -Value $CurrentPowerPlan.ElementName
  $OutputObj
 } else {
  write-Verbose "$Computer is offline"
 }
}            

}                        

end {}

 

Save the above code into a file called “Set-PowerPlan.ps1″ and it is ready for usage. You can use -ComputerName parameter if you want to run against a computer. If this parameter is not specified, it runs on local computer.

Go through the below examples for usage instructions and let me know if you have any questions.

Hope this helps…

Powershell: Get Active Directory Sites and subnets list

February 25, 2012 1 comment

This post talks about querying Active Directory Sites and subnets information from AD using Powershell. This script is helpful when you want to know subnets mapping to given site and servers lying in a site. This scrip doesn’t need much explanation since it is looking very straight forward. If you defer with me, please comment what part of script you want to understand. Also feel free to post if you would like to query any other information related to sites and services. Happy to help.

Code: Get-ADSites.ps1

[cmdletbinding()]
param()            

$Sites = [System.DirectoryServices.ActiveDirectory.Forest]::GetCurrentForest().Sites            

foreach ($Site in $Sites) {            

 $obj = New-Object -Type PSObject -Property (
  @{
   "SiteName"  = $site.Name;
   "SubNets" = $site.Subnets;
   "Servers" = $Site.Servers
  }
 )            

 $Obj
}

 Output

Powershell: Uninstall software on remote computer

February 20, 2012 2 comments

Ok. It’s time to uninstall a application using powershell. This post is continuation to Powershell: Script to query softwares installed on remote computer where I discussed about procedure to query installed applications on remote computer without using Win32_Product WMI class. The one advantage with Win32_Product WMI class is it’s uninstall() function using which we can trigger uninstallation of softwares on local or remote computer.

In this post, I am going to provide a powershell script which provides same functionality as uninstall() function of Win32_Product WMI class. My code uses GUID of product to trigger the uninstallation by passing it to msiexec process. It also triggers the uninstallation in silent mode so no UI will appear for the user while performing the uninstallation.

Code goes here…

[cmdletbinding()]            

param (            

 [parameter(ValueFromPipeline=$true,ValueFromPipelineByPropertyName=$true)]
 [string]$ComputerName = $env:computername,
 [parameter(ValueFromPipeline=$true,ValueFromPipelineByPropertyName=$true,Mandatory=$true)]
 [string]$AppGUID
)            

 try {
  $returnval = ([WMICLASS]"\\$computerName\ROOT\CIMV2:win32_process").Create("msiexec `/x$AppGUID `/qn")
 } catch {
  write-error "Failed to trigger the uninstallation. Review the error message"
  $_
  exit
 }
 switch ($($returnval.returnvalue)){
  0 { "Uninstallation command triggered successfully" }
  2 { "You don't have sufficient permissions to trigger the command on $Computer" }
  3 { "You don't have sufficient permissions to trigger the command on $Computer" }
  8 { "An unknown error has occurred" }
  9 { "Path Not Found" }
  9 { "Invalid Parameter"}
 }

Note that you need my previous script(Get-InstalledSoftware.ps1) and the one discussed in this article(Uninstall-InstalledSoftware.ps1) to make this uninstallation works since the code discussed in this article depends on the output of Get-InstalledSoftware.ps1 script.

Usage:

  1. Run Get-InstalledSoftware.ps1 script and note the GUID of application that you want to uninstall.
  2. Run Uninstall-InstalledSoftware.ps1 -GUID <<uninstall application GUID here>>

Uninstall-InstalledSoftware.ps1 -GUID “{54D3F6B5-515B-45B8-8F41-FC4D26FEFFEA}”

Test this script in test environment before you try on any production computer. Any improper use of this script can trigger the uninstallation of multiple applications if handled improperly.

This can made as single liner…..

.\Get-InstalledSoftware.ps1 -ComputerName MyPC1 | ? {$_.AppName -eq “iTunes” } | .\Uninstall-InstalledSoftware.ps1

This triggers the installation of iTunes applications. Please note that at any point of time you are passing the output single computer to Uninstall-InstalledSoftware.ps1.

This is just a initial version. I will enhance it to accept multiple computers and multiple uninstallations at same time. I will also make it more robust to track the uninstallation process.

Hope this helps..

Your comments are welcome

 

Powershell: How to logoff remote computer

February 19, 2012 Leave a comment

In my one of my recent posts, I talked about shutdown the remote computer using Powershell. Since then I started exploring the other options available in Win32_OperatingSystem class and figured out one more helpful method which can logoff users logged on remote computers.

This script helps you to logoff the remote user who is current loogged on the computer. I didn’t test this against terminal services environment where multiple users are logged in, but you can try this and let me know how it goes.

Code:

[cmdletbinding()]            

param (            

 [parameter(ValueFromPipeline=$true,ValueFromPipelineByPropertyName=$true)]
 [string[]]$ComputerName = $env:computername,
 [switch]$Force            

)            

begin {
 $Username = $env:username            

 if($force) { $flag = 4 } else { $flag = 0 }
 $comment  = "Logoff initiated by $Username using $($MyInvocation.InvocationName). Timeout is $Timeout"
}            

process {
 foreach($Computer in $ComputerName) {            

  Write-Verbose "Working on $Computer"
  if(Test-Connection -ComputerName $Computer -Count 1 -ea 0) {
   $OS  = Get-WMIObject -Class Win32_OperatingSystem -ComputerName $Computer
   if( -not $OS.Win32ShutdownTracker(0, $comment, 0, $flag)) {
    $Status  = "FAILED"
   } else {
    $Status  = "SUCCESS"
   }
  $OutputObj = New-Object -TypeName PSobject
  $OutputObj | Add-Member -MemberType NoteProperty -Name ComputerName -Value $Computer
  $OutputObj | Add-Member -MemberType NoteProperty -Name LogOffStatus -Value $status
  $OutputObj | Add-Member -MemberType NoteProperty -Name Timeout -Value $timeout
  $OutputObj
  }
 }
}            

end {
}

Usage:

.\Logoff-Computer.ps1 -ComputerName MyPC1

Powershell: Script to query softwares installed on remote computer

February 18, 2012 7 comments

Recently I came across a forum question where I have seen people using Win32_Product WMI class to get the installed installed applications list from remote computers. Historically, Win32_Product proved to be a buggy one due to various factors (which I will talk in later posts). So, I didn’t recommend them to use Win32_Product WMI class. If not WMI, what are the various options available to get the installed problems from remote computers. There are two methods (1) Using Win32Reg_AddRemovePrograms (2) Using Registry(uninstallkey).

The Win32Reg_AddRemovePrograms is not a common WMI class that you will find in any windows computer. It comes along with SMS or SCCM agent installation. So if you have one of these agents then probably you can explore this method. Otherwise, we need to rely on registry to get this information. Is the information queried from registry is accurate? My answer is YES and NO. It gives all the applications installed by both MSI installer and executables. But some of the registry keys will have less information about the software — not sure why it is that way.

Keeping the downsides aside, it is definitely the best approach to get installed softwares from remote computer. I am also excluding the applications from display if their display name black(which makes sense). This script will return the uninstall string as well which is essential for uninstalling the software. I will use this in my upcoming posts to uninstall a software remotely.

Now Code follows.

[cmdletbinding()]            

[cmdletbinding()]
param(
 [parameter(ValueFromPipeline=$true,ValueFromPipelineByPropertyName=$true)]
 [string[]]$ComputerName = $env:computername            

)            

begin {
 $UninstallRegKey="SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\Uninstall"
}            

process {
 foreach($Computer in $ComputerName) {
  Write-Verbose "Working on $Computer"
  if(Test-Connection -ComputerName $Computer -Count 1 -ea 0) {
   $HKLM   = [microsoft.win32.registrykey]::OpenRemoteBaseKey('LocalMachine',$computer)
   $UninstallRef  = $HKLM.OpenSubKey($UninstallRegKey)
   $Applications = $UninstallRef.GetSubKeyNames()            

   foreach ($App in $Applications) {
    $AppRegistryKey  = $UninstallRegKey + "\\" + $App
    $AppDetails   = $HKLM.OpenSubKey($AppRegistryKey)
    $AppGUID   = $App
    $AppDisplayName  = $($AppDetails.GetValue("DisplayName"))
    $AppVersion   = $($AppDetails.GetValue("DisplayVersion"))
    $AppPublisher  = $($AppDetails.GetValue("Publisher"))
    $AppInstalledDate = $($AppDetails.GetValue("InstallDate"))
    $AppUninstall  = $($AppDetails.GetValue("UninstallString"))
    if(!$AppDisplayName) { continue }
    $OutputObj = New-Object -TypeName PSobject
    $OutputObj | Add-Member -MemberType NoteProperty -Name ComputerName -Value $Computer.ToUpper()
    $OutputObj | Add-Member -MemberType NoteProperty -Name AppName -Value $AppDisplayName
    $OutputObj | Add-Member -MemberType NoteProperty -Name AppVersion -Value $AppVersion
    $OutputObj | Add-Member -MemberType NoteProperty -Name AppVendor -Value $AppPublisher
    $OutputObj | Add-Member -MemberType NoteProperty -Name InstalledDate -Value $AppInstalledDate
    $OutputObj | Add-Member -MemberType NoteProperty -Name UninstallKey -Value $AppUninstall
    $OutputObj | Add-Member -MemberType NoteProperty -Name AppGUID -Value $AppGUID
    $OutputObj# | Select ComputerName, DriveName
   }
  }
 }
}            

end {}

Copy this code to a text file and save it as Get-InstalledSoftware.ps1. Look at the below image for usage.

Powershell: Move Computer accounts from default container to specific OU

February 18, 2012 9 comments

Whenever a computer is added to a windows domain, by default account will get created under Computers container. It is located right below the domain name in dsa.msc. The pull of it is, <domainName>\Computers.

Today one of my friend has asked to know if there any quick script using which he can move all computers from default computers container to OU of his choice in same domain. Since I don’t have a script already authored for this purpose, I quickly made the below.

This is a very basic version of computer accounts movement script. There might be some conditions processing like if name contains XYZ move to one OU or if name contains ABC move to different OU. You can accommodate such conditions in this script if you have little powershell knowledge(or let me know I can help you given some time).

Here is the code.

[cmdletbinding()]            

param (
[parameter(mandatory=$true)]
$TargetOU
)            

Import-Module ActiveDirectory
$Domain = [ADSI]""
$DN=$domain.distinguishedName
$SourcePath = "CN=Computers," + $DN
$Computers = Get-ADComputer -Filter * -SearchBase $SourcePath
if(!$Computers) {
 write-host "No Computers are found in default container"
 return
}
foreach ($Computer in $Computers) {
 if(!(Move-ADObject $Computer -TargetPath $TargetOU)) {
  $Status = "SUCCESS"
 } else {
  $Status = "FAILED"
 }
 $OutputObj = New-Object -TypeName PSobject
 $OutputObj | Add-Member -MemberType NoteProperty -Name ComputerName -Value $Computer.Name.tostring()
 $OutputObj | Add-Member -MemberType NoteProperty -Name SourcePath -Value $SourcePath
 $OutputObj | Add-Member -MemberType NoteProperty -Name DestinationPath -Value $TargetOU
 $OutputObj | Add-Member -MemberType NoteProperty -Name Status -Value $Status
 $OutputObj
}

 

When I executed this script in my test domain for testing purpose it went fine and generated below output. This script is not depending on any external modules/cmdlets like quest tools. I uses ActiveDirectory module which comes with RSAT(or windows 2008 domain controllers). Needless to say that you need ADWS(active directory web services) installed if all your domain controllers are Windows 2003. This is not required if atleast one DC is having windows 2008 R2 OS where ADWS is default.

Output:

PowerShell: Get individual process count

February 17, 2012 Leave a comment

I am a very bad user of my PC. I open many IE, notepad and other application windows sand leave them like that. I only care to close them only when my computer starts behaving crazy :-/

Today I did the same exercise of closing old/unused application windows to give some breathing room for my computer. While doing it I was curios to know what is the count of each process running on my computer so that I can see the top processes and close the ones which are high in number. And immediately, I authored this script.

[cmdletbinding()]            

param(
$ComputerName = $env:computername
)
$Processes = Get-Process -ComputerName $ComputerName
$myprocesses = @()
foreach($process in $processes) {
  $myprocesses = $myprocesses + $process.Name
}
$hash =@{}
$myprocesses | % {$hash[$_] = $hash[$_] + 1 }
$hash.getenumerator() | ? { $_.value -gt 1 } | sort value

All I am doing is reading the process names into a array called $myprocesses and applying the one of my previous powershell inventions which can detect the duplicates in an array and give the count. This one proved to be handy for me many times.

So, after executing the script, I can see that too many notepad.exe processes are running….. Thank you PS. I will close them first. :-)

Thank you for reading. Let me know if you come across this small tip handy anywhere.

Happy reading…

 

Powershell: Get IP Address, Subnet, Gateway, DNS servers and MAC address details of remote computer

February 17, 2012 5 comments

What are the IP address details of remote computer? When even I came across this question while troubleshooting some problem, I do nothing but logging on to the servers to see the details. Isn’t this a time consuming process? what if I want to get these details using some automation. Unfortunately, there is no windows built-in command like ipconfig /system:mypc1 to get the IP details. So, I decided to make a powershell script which addresses this purpose.

[cmdletbinding()]
param (
 [parameter(ValueFromPipeline=$true,ValueFromPipelineByPropertyName=$true)]
    [string[]]$ComputerName = $env:computername
)            

begin {}
process {
 foreach ($Computer in $ComputerName) {
  if(Test-Connection -ComputerName $Computer -Count 1 -ea 0) {
   $Networks = Get-WmiObject Win32_NetworkAdapterConfiguration -ComputerName $Computer | ? {$_.IPEnabled}
   foreach ($Network in $Networks) {
    $IPAddress  = $Network.IpAddress[0]
    $SubnetMask  = $Network.IPSubnet[0]
    $DefaultGateway = $Network.DefaultIPGateway
    $DNSServers  = $Network.DNSServerSearchOrder
    $IsDHCPEnabled = $false
    If($network.DHCPEnabled) {
     $IsDHCPEnabled = $true
    }
    $MACAddress  = $Network.MACAddress
    $OutputObj  = New-Object -Type PSObject
    $OutputObj | Add-Member -MemberType NoteProperty -Name ComputerName -Value $Computer.ToUpper()
    $OutputObj | Add-Member -MemberType NoteProperty -Name IPAddress -Value $IPAddress
    $OutputObj | Add-Member -MemberType NoteProperty -Name SubnetMask -Value $SubnetMask
    $OutputObj | Add-Member -MemberType NoteProperty -Name Gateway -Value $DefaultGateway
    $OutputObj | Add-Member -MemberType NoteProperty -Name IsDHCPEnabled -Value $IsDHCPEnabled
    $OutputObj | Add-Member -MemberType NoteProperty -Name DNSServers -Value $DNSServers
    $OutputObj | Add-Member -MemberType NoteProperty -Name MACAddress -Value $MACAddress
    $OutputObj
   }
  }
 }
}            

end {}

This script is pretty much self explanatory. It uses Win32_NetworkAdapterConfiguration WMI class to get the network configuration details. This script also helps you to get DNS servers, MAC address details, subnetmask and default gateway details. Using this script you can also know the list of network adapters that has DHCP enabled/disabled(means static IPs).

You can save this script to a PS1 fil(say Get-IPDetails.PS1) and run it against list of computers you need. Below is one example.

Hope this helps…