≡ Menu

“The attempt to connect to http://ExchangeServer.domain.com/PowerShell using “Kerberos” authentication failed: connecting to remote server failed with the following error message : The WinRM client cannot complete the operation within the time specified.  Check if the machine name is valid and is reachable over the network and firewall exception for Windows Remote Management service is enabled.  For more information, see the about_Remote_Troubleshooting Help topic.”

You might notice above error message after opening a Exchange Management Console. This error message indicates that connecting to given exchange server using WinRM has failed. Today I received the same error and verified that exchange is doing well on this box. I tried opening the console from different server and it worked file. So, it appeared some sort of profile problem to me.

I did the following to resolve the issue.

  1. Close Exchange Management Console MMC
  2. Go to %appdata%\Microsoft\MMC
  3. Rename “Exchange Management Console” file to “Exchange Management Console.old”
  4. Launch the console again.

Hope this helps…

{ 5 comments }

Today I got a requirement to see if a computer account was placed in maintenance mode or yesterday. If yes, I would like to see maintenance window details and the username who did it.

Given that there no GUI option in SCOM to get this information, I explored the powershell way and finally came-up with below script.

function Get-SCOMMaintenanceModeHistroy {            

[cmdletbinding()]            
param (            
 [parameter(mandatory=$true)]            
 [string]$computerName,            
 [parameter(mandatory=$true)]            
 [string]$RootmanagementServer            

)            

Add-PSSnapin Microsoft.EnterpriseManagement.OperationsManager.Client -ErrorAction 0 | Out-Null            
new-managementGroupConnection -ConnectionString:$RootmanagementServer | out-null            
Push-Location -Path "OperationsManagerMonitoring::" -ErrorAction:Stop               
$agent = Get-Agent | Where-Object {$_.displayname -match $ComputerName}            
$MaintenanceObj = Get-MaintenanceWindow -MonitoringObject $agent.HostComputer -History -ErrorAction 0            
  if($MaintenanceObj) {            
   $output = New-Object -Type PSObject -Property @{            
    ComputerName = $Computername            
    StartTime  = ($MaintenanceObj.Starttime).tolocaltime()            
    EndTime   = ($MaintenanceObj.ScheduledEndTime).Tolocaltime()            
    UserName  = $MaintenanceObj.User            
    Comment   = $MaintenanceObj.Comments            
   }            
   $Output | select ComputerName, StartTime, EndTime, UserName, Comment | ft -wrap            
  } else {            
   write-Error "Unable to get the maintenance mode of $ComputerName"            
  }            
Pop-Location            
}

There are some SQL queries around the web and you can use them if you want. You can find one such thing at http://sys-man.blogspot.com/2011/03/scom-2007-r2-maintenance-mode-history.html. I am not sure about the functionality of this SQL code. Please get this tested in test bed before you try in production.

Hope this helps and happy learning…

{ 2 comments }

From long time I have been thinking to have a powershell function which captures the output of a function/command and sends it to windows clipboard so that I can paste it where ever I want. But I failed to do that from time to time due to other commitments. Recently I came across a post from powershell.com which talked about the same topic. You can view the post at http://powershell.com/cs/blogs/tips/archive/2012/01/03/sending-text-to-clipboard-everywhere.aspx. I went through this post multiple times to understand what it is doing. Honestly, I am not good with windows forms or for that matter using dotnet classes from powershell. This code made me curious enough to read and understand windows forms as it used a System.Windows.Forms.TextBox class in it. I wondered why we need to use Textbox class to copy something from console to clipboard. After spending decent enough time, it turned out that the author of that function just wanted to utilized the Copy() function of that class which helps you to copy something to clipboard.

After understanding the code better, I felt usage of textbox class is somewhat unnecessary when dotnet providing separate classes to do clipboard operations. I continued my readings on bringing dotnet classes to powershell and finally came up with below code which copies the output of a cmdlet/function to clipboard.

You might want to ask, why I have to write the code again when I have something working. Well, there is nothing wrong with the code, I can happily use it. But if that requires expansion it terms of copying images to clipboard, handling data text formats, etc, that code is not efficient as TextBox doesn’t provide any methods to perform that. Given these reasons, I rewrote the function using Windows.Forms.Clipboard so that this can be expanded to perform variety of clipboard operations. Read http://msdn.microsoft.com/en-us/library/system.windows.forms.clipboard.aspx to understand different activities you can perform using this clipboard class.

Another thing is that, the function given by powershell.com is not porting the command executed to the clipboard which I feel valid because I(or people viewing the output) should know to what command the output belongs.

Well here is the modified version of Set-Clipboard function and hope you like this.

function Set-Clipboard {            
<#
    .Synopsis
        Sets the system clip board with either output of a command/function/cmdlet or given text

    .Description
        This function takes the $input from pipeline and sends it to clipboard so that we can paste the output wherever we want.
        
    .Parameter Text
        Text string that you want to store in clipboard
    
    .Example
        Example 1:
        Get-Process | Set-Clipboard
        
        Example 1:
        Set-Clipboard -Text "Copy this string to clipboard"
        
    .Notes
        NAME:        Set-ClipBoard
        AUTHOR:        Sitaram Pamarthi
        WEBSITE:    https://techibee.com
#>
 param (            
  $Text            
 )            

 if($text) {            
  $Clipboardtext = $text            
  [Windows.Forms.Clipboard]::SetText($clipboardtext)            
 } else {            
  $prompt = prompt            
  $clipboardtext = $prompt + $($myinvocation.line) + $($input | out-string)            
 }            
 [Windows.Forms.Clipboard]::SetText($clipboardtext)            
 $null = [Reflection.Assembly]::LoadWithPartialName("System.Windows.Forms")             
}

PS C:\> Get-Process | Set-Clipboard

PS C:\>Set-Clipboard -Text “Copy me to clipboard”

Hope this helps and comments are welcome.

 

 

 

{ 4 comments }

I was hit with this requirement today. I need to change date and time from my local system time zone to another time zone (say “Eastern Standard Time”). After some research I finally came up with below function which does what I need.

This function uses a dotnet class called [System.TimeZoneInfo] which had methods to see all timezones available local system, convert from one time zone to another, day light savings offsets and many more.

function Convert-TimeZone {            
<#
    .Synopsis
        Converts given datetime from local time zone to another given time zone

    .Description
        This function helps you to convert date time information from local time zone to another time zone.
        
    .Parameter DateTime
        A datetime object which needs to be converted to different time zone.
    
    .Parameter ToTimeZone    
        Name of the target time zone. If you don't have name of the target time zone, then try below command
        from powershell console which displays all available timezones that you can convert.

        [system.timezoneinfo]::GetSystemTimeZones()
    
    .Example
        Convert-TimeZone -DateTime (get-now) -ToTimeZone "Eastern Standard Time"
                
    .Notes
        NAME:      Convert-TimeZone
        AUTHOR:    Sitaram Pamarthi
        WEBSITE:   https://techibee.com

#>

 [cmdletbinding()]            
 param (            

  [parameter( Mandatory=$true)]            
  [ValidateNotNullOrEmpty()]            
  [datetime]$DateTime,            
  [string]$ToTimeZone  = ([system.timezoneinfo]::UTC).id            

 )            

 $ToTimeZoneObj  = [system.timezoneinfo]::GetSystemTimeZones() | Where-Object {            
        $_.id -eq $ToTimeZone            
       }            

 if(!($ToTimeZoneObj)) {            
        Write-Error "Zone Conversion failed. Given timezone is not valid. Choose the target time zone from list of below given zones"            
        return            
    }            
 $TargetZoneTime  = [system.timezoneinfo]::ConvertTime($datetime, $ToTimeZoneObj)            

 $Output    = New-Object -TypeName PSObject -Property @{            
  LocalTime  = $datetime            
  LocalTimeZone = $(([system.timezoneinfo]::LOCAL).id)            
  TargetTime  = $TargetZoneTime            
  TargetTimeZone = $($ToTimeZoneObj.id)            
 }            
 $Output | select LocalTime, LocalTimeZone, TargetTime, TargetTimeZone | ft            
}

Usage:

Convert-TimeZone -DateTime (get-date) -ToTimeZone “Eastern Standard Time”

Output:

Hope this helps… soon I will try to come up with enhancement to this to convert date time from one time zone to another time zone irrespective of local system time zone.

 

{ 5 comments }

Querying and changing BIOS from operating system is never been easy. The only useful BIOS thing that we can get from Operating System is serial number. But if you want to know the settings like boot order, TPM setting level, change BIOS password, and status of Wake on LAN setting etc, you should shut down your system and enter into BIOS.

Hardware manufacturers started noticing our(System Administrator’s) troubles some time ago and started delivering good tools using which we can manage BIOS from Operating System itself. If you can manage BIOS settings from Operating System, then you can obvious be able to automate them using one of the Scripting languages as well.

In this “Managing Dell Computers BIOS using PowerShell” series, I will take you through preparing your desktop environment to allow BIOS query from operating system, different settings we can query, how to use powershell to query and set BIOS settings. Given the hardware resources limitation I have, I am going to limit the scope of this post series to DELL hardware and touch the basics of other hardware’s.

Now let us go and see how we can prepare our DELL desktop environment for BIOS query from Operating System.

The manufacturer, DELL, is providing a MSI installer called OMCI (Open Manage Client Instrumentation) which you can install on a DELL PC. This installation creates a set of WMI classes in the operating system which has functions and that allows you to query and set BIOS. This OMCI util is available for both 64-bit and 32-bit operating systems.

This OMCI util is available for Dell Optiplex, Dell Precision, and Dell Latitude hardwares only.

 

Procedure to install and deploy OMCI:

  1. Download the OMCI version that matches your hardware and OS version.
  2. Launch the downloaded executable to extract setup.exe
  3. Execute setup.exe to install OMCI.

Setup.exe has command line options as well which you can use to automate the installation via your software deployment tool. You can use below command to install the OMCI tool in silent mode.

setup.exe /s /v”/qn REBOOT=ReallySuppress /l %windir%\temp\OMCI.log”

All this command does is installation of OMCI utility in silent mode. For more command line options look at the below image.

Once the installation is completed, your computer is ready for using the DELL BIOS related WMI classes. To see list of WMI classes that are added with OMCI, try the below command. DELL OMCI installs approximately 206 WMI classes which severs different purposes. You should note here that, accessing the information via DELL OMCI classes works only with administrator accounts. Normal users can not query these classes. May be we can grant custom permissions to allow normal users to query these classes but I want to keep it away from the scope for now.

Get-WmiObject -Namespace root\dellomci -list | select Name

I don’t want to complete this part-1 of “Managing Dell Computers BIOS Settings using PowerShell series” without an example. Here is the one. Below examples helps you to quickly identify the boot sequence of a computer.

Get-WmiObject -NameSpace root\dellomci Dell_BootDeviceSequence | sort bootorder | select BootDeviceName, BootOrder

And the output of above command will look like below.

In my next post I will write about how to enable wake on lan using Powershell and DELL OMCI classes.

Hope this is helpful… and stay tuned.

{ 3 comments }

I feel this post doesn’t require much explanation. We all know FSMO roles and their important. This little powershell script helps you query active directory FSMO roles from your domain/forest.

I have seen some more examples about the same topic in internet but all of them are using dotnet objects to get this information or running the command lines and parsing the information to generate the data. I feel this is not necessary as the built-in activedirectory module is providing this information in a very straight forward way.

function Get-AdFSMORoles {            
[cmdletbinding()]            
param()            

$AdFSMORoles = New-Object -TypeName PSobject            

import-module activedirectory            
$DomainRoles = Get-ADDomain            
$ForestRoles = Get-ADForest            

$AdFSMORoles | Add-Member -MemberType NoteProperty -Name InfraStructureMaster -Value $DomainRoles.InfraStructureMaster            
$AdFSMORoles | Add-Member -MemberType NoteProperty -Name RIDMaster -Value $DomainRoles.RIDMaster            
$AdFSMORoles | Add-Member -MemberType NoteProperty -Name PDCEmulator -Value $DomainRoles.PDCEmulator            
$AdFSMORoles | Add-Member -MemberType NoteProperty -Name SchemaMaster -Value $ForestRoles.SchemaMaster            
$AdFSMORoles | Add-Member -MemberType NoteProperty -Name DomainNamingMaster -Value $ForestRoles.DomainNamingMaster            

$ADFSMORoles | fl            
}

Hope this helps…

 

{ 4 comments }

This post helps you to understand how to query nested group members using powershell. The MS given ActiveDirectory powershell module doesn’t provide a direct way to get all the members part of a security group. This information is useful because you can know who all will get permissions granted to a particular security group if the security group has sub groups inside it. If there is just one or two levels of sub groups, then maybe we can spend time and write code for querying those groups as well by parsing their names. But how we can handle the situation where we don’t know how many sub groups the group we are querying has and how many levels are there?

To address this requirement I have written a small powershell function that helps you to get all direct and indirect members of a security group in active directory.

function Get-ADNestedGroupMembers {
[cmdletbinding()]
param (
[String] $GroupName
)            

import-module activedirectory
$Members = Get-ADGroupMember -Identity $GroupName
$members | % {
    if($_.ObjectClass -eq "group") {
        Get-ADNestedGroupMembers -GroupName $_.distinguishedName
    } else {
        return $_.distinguishedname
    }
}            

}

In this code I am using Get-ADGroupMember cmdlet which is part of activedirectory module. This code uses recursive function call to query group members when a sub group is found.

Usage:

Hope this helps… please feel free to post in comments section if you have any questions. This script can be enhanced to display objects of a particular type — for example, only computers, only users etc. I am doing it here …but let me know if you have the requirement, I will add the code for that as well.

You can export the output to a file using below command.

Get-ADNestedGroupMembers -GroupName "Test1" | out-file -Filepath c:\temp\test1.txt

 

Hope this helps…

{ 10 comments }

Adding domain groups to local administrators group on remote computers(servers/workstations) is most common activity any system administrator do. I got similar task today and realized that I don’t have a PowerShell function to do. We know it is simple and can build command on fly, but having a function is much more useful. So, I have written below function and added to my techibee module(will publish this soon).

This script takes three arguments. 1) ComputerName — on which you want to do this operation. 2)GroupName — that you want to add to the local administrators group of remote computer 3) DomainName — an optional parameter using which you can pass the domain name if the group you are adding belongs to different domain that of your computer is currently in.

function Add-DomainGroupToLocalAdministrator {
param (
[parameter(Mandatory = $true)]
$ComputerName,            

[parameter(Mandatory = $true)]
$GroupName,            

$DomainName
)            

if(!($DomainName)) {
    Import-Module ActiveDirectory
    $DomainName = (Get-AdDomain).DNSRoot.ToString()
}            

try {            

    $AdminGroup = [ADSI]("WinNT://$ComputerName/Administrators,Group")
    $AdminGroup.Add("WinNT://$DomainName/$GroupName,Group")
    Write-host "Successfully Added $GroupName to local administrators group of $computerName"            

}
catch {
    Write-Error $_
}            

} 

Hope this helps…

{ 2 comments }

How to get Group Policy permissions using powershell

Using PowerShell, we can query who has permissions to a given GPO or a list of GPOs. We can do this either using Quest Active Roles cmdlets or by using native cmdlets that comes along with Windows 7 installation. In this post, I am going to demonstrate and show you the native method. To use the native method, you must be running one of the following:

  • Windows Server 2008 R2 on a domain controller
  • Windows Server 2008 R2 on a member server that has the GPMC installed
  • Windows® 7 with Remote Server Administration Tools (RSAT) installed. (RSAT includes the GPMC and the Group Policy cmdlets)

GPMC(or RSAT) installation also installs a powershell module called grouppolicy using which we can query the GPOs. Before start dealing with GPOs, we should import this module by using import-module GroupPolicy command.

Below is the sample code that helps you get permissions of a give a GPO.

function Get-GPOPermissions {            

param($GpoName)
import-module GroupPolicy            

$permsobj = Get-GPPermissions -Name $GPOName -All
foreach ($perm in $permsobj) {            

    $obj = New-Object -TypeName PSObject -Property @{
   GPOName  = $GPOName
   AccountName = $($perm.trustee.name)
        AccountType = $($perm.trustee.sidtype.tostring())
        Permissions = $($perm.permission)
 }
$obj | Select GPOName, AccountName, AccountType, Permissions            

}
}

Below is the sample output:

Hope this helps. I will continue writing some GPO related scripts in coming days.

 

 

{ 3 comments }

In this post you will learn how to query SCOM RMS server name of a specific SCOM group using powershell script.

In all my SCOM scripts that I wrote so far, I hardcoded the SCOM RMS server name. Recently I came across a situation where RMS role is moved to another management server in same SCOM group. With this change, obviously all my scripts will fail because the hard coded server is not a RMS server anymore and it has no intelligence to redirect my query to the current RMS sever.

That means we should have a dynamic way using which we can get RMS server automatically from some reliable source. SCOM installations creates a SCP(Service Connection Point) in Active directory for each SCOM group. So now I will show you how to query this SCP using powershell and get the RMS server name.

We can either choose to use build-in Activedirectory module or Quest AD Cmdlets to get information. The below code is based on activedirectory module which is available with Windows 2008 and Windows 7.

function Get-ScomRMSServer {            
            
Import-Module ActiveDirectory            
$Domainname = (Get-ADDomain).DistinguishedName.tostring()            
$SCOMObj = Get-ADObject -Filter "Name -eq 'SDKServiceSCP'" -SearchBase $domainname `
-Properties ServiceDNSName, ServiceClassName            
$SCOMObj | select serviceclassname, serviceDNSName            
            
}

Thanks to my colleague(Deepesh) who helped with finding this.

 

{ 1 comment }