View all posts filed under 'PowerShell'

How To Remotely Administer A Citrix Farm From The PowerShell Prompt?

Thursday, 10. June 2010 14:15

If you’re using Windows PowerShell to administrer and automate Citrix Farms the day will dawn when you ask yourself (or someone else) if it is possible to fire up the locally installed Windows PowerShell Console in order to perform a task against a Citrix Farm remotely. Yes, it is possible

In case of XenApp 6 you make use of PowerShell 2.0′s Remoting feature as follows:

#
# Remote XenApp 6 w/ PowerShell 2.0 Remoting
#
$CitrixServer = 'ctx001'

$session = New-PSSession -ComputerName $CitrixServer
Enter-PSSession -Session $session

Add-PSSnapin Citrix*

In case of MFCOM-based Legacy Farm Server you can either create a PowerShell Remoting Session like above or – if you still use PowerShell 1.0 you have no other choice – create a remote COM object:

#
# Remote MFCOM w/ PowerShell 2.0 Remoting
#
$CitrixServer = 'ctx001'

$session = New-PSSession -ComputerName $CitrixServer[activator]::CreateInstance($type, $null)
Enter-PSSession -Session $session

$farm = New-Object -ComObject 'MetaFrameCOM.MetaFrameFarm'

#
# Remote MFCOM w/ PowerShell 1.0 and .NET
#
$CitrixServer = 'ctx001'

$type = [type]::GetTypeFromProgID('MetaFrameCOM.MetaFrameFarm', $CitrixServer)

$farm = [activator]::CreateInstance($type, $null)

Category:Citrix, PowerShell | Comment (0) | Author: Frank-Peter

How To Migrate A “Legacy” Citrix Farm To XenApp 6?

Wednesday, 9. June 2010 15:01

Recently, I wrote here about the release of the Citrix XenApp 6 PowerShell SDK and that XenApp 6 neither supports nor contains the MFCOM programming interface of XenApp 5 and older versions (which I will call Legacy Farm from now on).

Upcoming Legacy Farm to XenApp 6 migration projects will definitely go along with the requirement to automatically export the Legacy Farm’s objects like Applications or Administrators in order to import them into the new XenApp 6 Farm. Since XenApp6 has no MFCOM support you won’t be able to use MFCOM based migration scripts you may have written for former migration projects. What you need instead is a Migration Tool that “speaks” both MFCOM and XenApp 6 Commands – meaning a tool that is able to communicate with the Legacy Farm as well as the new farm.

Good news is that such a tool is already available, currently it is still in Beta and it is supposed to be released in mid of this month – the Citrix XenApp 6 Migration Tool (Download)

The XenApp 6 Migration Tool contains a PowerShell 2.0 Module whose Cmdlets and Functions can be used to export Legacy Farm settings from a XenApp 5 Farm and import them to a XenApp 6 Farm. The following types of objects can be migrated:

  • Application
  • Folder
  • Load evaluator
  • Policy
  • Server configuration
  • Farm configuration
  • Administrator

Settings you can’t transfer:

  • Zones
  • Printer management
  • Configuration logging settings

The XenApp 6 Migration Tool supports only migration from a single XenApp 5 Farm. It isn’t possible to consolidate multiple Legacy Farms into one XenApp 6 Farm. The Legacy Farm must be based on XenApp 5 for WS2003 + HRP5 or XenApp 5 for WS2008. The new farm must be running XenApp 6 for WS2008 R2.

Category:Citrix, PowerShell | Comment (0) | Author: Frank-Peter

XenApp 6 PowerShell SDK Released

Sunday, 9. May 2010 17:16

About two weeks ago Citrix has released the XenApp 6 PowerShell SDK that enables people to manage XenApp 6 farms using Microsoft PowerShell scripting. The modules included in the SDK are Citrix XenApp Commands (aka XenApp cmdlets), Citrix Group Policy Provider, and Citrix Common Commands. The Citrix Principal Design Engineer Tom M Kludy wrote some nice blogs about the XenApp 6 SDK.

Reading the XenApp cmdlets reference I found the following information for those of you who are familiar with MFCOM:

Starting in XenApp 6.0, MFCOM as a publically supported programming and scripting interface will no longer be available. All existing MFCOM-based code no longer works on XenApp 6.0. No doubt that the absence of MFCOM will be something that requires additional effort to the adoption of XenApp 6.0.

Take a deep breath and don’t panic! Most of MFCOM scripts can be replaced by one-liners meaning that most of the short MFCOM scripts are obsolete as they’ve been replaced by PowerShell cmdlets.

For example adding a Citrix admin with the XenApp 6 PowerShell SDK is a one-liner:

New-XAAdministrator –AdministratorName ctxadmin –AdministratorType Full

In MFCOM, an administrator would need to write a script with dozens lines of code like below to accomplish the same task. So after all, it was definitely a good idea to discontinue MFCOM Support.

function Test-IsCitrixAdministrator(){

	$MetaFrameWinFarmObject = 1

	$MFCOM = New-Object -ComObject 'MetaframeCOM.MetaFrameFarm'
	if (!$MFCOM)
	{
		$result = $false
	}
	else
	{
		$MFCOM.Initialize($MetaFrameWinFarmObject)
		$result = [boolean] $MFCOM.WinFarmObject.IsCitrixAdministrator
		$MFCOM = $null
	}
	$result
}

function Test-ADGroup(){

	param(
		$name = $(throw "No AD group name specified.")
	)

	$domainRoot = [System.DirectoryServices.ActiveDirectory.Forest]::GetCurrentForest().RootDomain.Name
	$searcher = New-Object System.DirectoryServices.DirectorySearcher([ADSI]"GC://$domainRoot")
	$searcher.Filter = "(&(objectClass=Group)(name=$name))"
	$result = $searcher.FindOne()
	[boolean] $result
}

function Add-CitrixAdmins(){

	param(
		$accounts = $(throw "No comma-seperated list of Citrix Admin accounts specified."),
		$adminType = $(throw "No Admin Type specified. (Full or ViewOnly?)")
	)

	$MetaFrameWinFarmObject     = 1
	$MFAdminPermissionViewOnly  = 1
	$MFAdminPermissionFullAdmin = 3
	$MFAccountAuthorityADS      = 3
	$MFAccountGlobalGroup       = 4
	$MFAccountEnable            = 1

	switch($adminType)
	{
		"Full"
		{
			$MFAdminPermission = $MFAdminPermissionFullAdmin
		}

		"ViewOnly"
		{
			$MFAdminPermission = $MFAdminPermissionViewOnly
		}

		default
		{
			throw "This function supports only the Citrix Admin Privilege levels Full and ViewOnly."
		}
	}

	$MFCOM = New-Object -ComObject 'MetaframeCOM.MetaFrameFarm'
	$MFCOM.Initialize($MetaFrameWinFarmObject)

 	$currentAdmins = $MFCOM.Admins | %{$_.FriendlyName}
	$newAdmins     = $accounts.Split(",")

	$defaultDomain = $env:USERDOMAIN

	foreach($account in $newAdmins)
	{
		$newAdmin = $account.Split("\")
		if($newAdmin.Count -eq 1)
		{
			$accountDomain = $defaultDomain
			$accountName = $account
			if (-not (Test-ADGroup $accountName)){throw "Group does not exist in $accountDomain - $accountName"}
		}
		else
		{
			$accountDomain = $newAdmin[0]
			$accountName = $newAdmin[1]
		}

		if($currentAdmins -notcontains "$accountDomain\$accountName")
		{
			$mfAdmin = $MFCOM.AddAdmin()
			$mfAdmin.AdminType = $MFAdminPermission
			$mfAdmin.AAType = $MFAccountAuthorityADS
			$mfAdmin.AAName = $accountDomain
			$mfAdmin.AccountType = $MFAccountGlobalGroup
			$mfAdmin.AccountName = $accountName
			$mfAdmin.Enable = $MFAccountEnable
			$mfAdmin.SaveData()
			$mfAdmin = $null
		}
	}
}

Category:Citrix, PowerShell | Comments (3) | Author: Frank-Peter

Default Import-Module behavior

Saturday, 10. April 2010 21:31

Ok, we all know modules in Powershell 2.0 are very cool… For me, probably the best of all newly introduced concepts is namespace support.

To make long story short – if I import function Get-Command from module SCCM, I can access it using namespace – SCCM\Get-Command.

Looks really pretty, is secured and you can use consistent function names in different modules, which is perfect from usability perspective.

You don’t need to use namespaces if you don’t want to however. So you can either use SCCM\Get-Command OR Get-Command.

Problem is that when you use Import-Module, last one always wins. So my SCCM\Get-Command still works fine, however of course it will overwrite Get-Command.

I think this is extremely dangerous behavior. If you also thing it should be changed, please vote here. My proposal is that Import-Module should get switch that will identify that all exported objects are accessible by specifying namespace also.

As a workaround, you can use following code:

Get-Command -CommandType cmdlet | ForEach-Object {Set-Alias -Name $_.Name -Value "$($_.PSSnapIn)\$($_.Name)"}

Insert this code at beginning of your script and it will take care that you won’t be able to accidentally overwrite existing cmdlets (aliases always wins).

 

Martin

Category:PowerShell, Scripting, Windows PowerShell | Comment (0) | Author: Martin Zugec

WeekOfMonth

Tuesday, 9. March 2010 19:05

Today I needed small function to determine what is the number of current week (usually referred as WeekOfMonth).

Code is very simple in fact:

Function Get-WeekOfMonth ([datetime]$Date = $(Get-Date)) {
	[int]$Day = $Date.Day
	Return [math]::Ceiling($Day / 7)
}

 

Martin

Category:General, PowerShell, Scripting, Windows PowerShell | Comment (0) | Author: Martin Zugec

Powershell coding style

Wednesday, 24. February 2010 10:41

I was reading very interesting post from Jeffrey Hicks called PowerShell Picasso today and I must say that I agree with him 99%.

If you know the way I script, then you have probably noticed that it is hybrid code between PowerShell and .NET. For example I don’t like ForEach-Object cmdlet – from my perspective, it makes code much LESS readable. I would compare it to question sentence in English and in Spanish. In Spanish, every question sentence begins with question mark (for example ¿Cómo estás?) and you immediately know it is going to be the question.

For same reason, I always use ForEach ($X in $Y) {…}. I find it much easier to undestand $X. than $_… If I have a quick peek at code, using $Service.Status immediately tells me what I need, while $_.Status requires me to read preceding code to understand what type of object is $_. Organizing code to blocks is my preferred method (while many Powershell guys organize code to sentences :) ).

Second side effect is that by using .NET syntax, people much quickly adopt the fact that Powershell is based on .NET object and is object-oriented language. Later on, these administrators can read and understand MSDN documentation or examples that are written in C#. To summarize it, my point is that for many people, Powershell can be used as entry point to .NET world (.NET for Administrators).

I fully agree with rest of the Jeffrey’s article. “Problem” as I see it is that most people use Posh in interactive mode – and there is huge difference in writing few functions for yourself and trying to build complex framework out of Powershell (just checked – my framework currently consists of almost 4000 files, even though it is based on modules). In case you don’t think about readability of your code, you will get lost when you will need to write the complex modules (thousands of lines).

Martin

Category:General, Gotcha, PowerShell, PowerShell News, Scripting, Windows PowerShell | Comment (0) | Author: Martin Zugec

Working with local administrator

Wednesday, 17. February 2010 21:52

When working with local administrator account, there are 3 possible tasks you usually want to accomplish:

1.) Change password

2.) Rename account

3.) Disable\Enable account

Below are snippets of Powershell code that can help you to achieve that. First line is always used to retrieve local account with RID 500 (built-in administrator account, no matter what is the name), rest than depends on what you want to achieve.

1.) Change password

<P>$LocalAdministrator = $(Get-WmiObject –Query ‘Select * from Win32_UserAccount
Where (LocalAccount="True" and SID like "%-500")’)</P>
<P>$AdminReference = [adsi]("WinNT://./" + $LocalAdministrator.Name + ", user")
$AdminReference.psbase.invoke("SetPassword", "new and shiny password")</P>

2.) Rename account

<P>$LocalAdministrator = $(Get-WmiObject –Query ‘Select * from Win32_UserAccount
Where (LocalAccount="True" and SID like "%-500")’)</P>
<P>$LocalAdministrator.Rename("LocalAdmin")</P>
<P>$LocalAdministrator.Put()</P>

3.) Disable\Enable account

<P>$LocalAdministrator = $(Get-WmiObject –Query ‘Select * from Win32_UserAccount
Where (LocalAccount="True" and SID like "%-500")’)</P>
<P>$LocalAdministrator.Disabled = $False</P>
<P>$LocalAdministrator.Put()</P>

Martin

Category:General, PowerShell | Comment (0) | Author: Martin Zugec

Zero Touch Installation with MDT 2010

Tuesday, 16. February 2010 10:59

Henk Hofs – known as the geek with an opinion ;-) – has posted a nice PowerShell script to achieve ZTI functionality with Microsoft Deployment Toolkit 2010: ZeroTouch for MDT 2010 without SCCM!

Category:General | Comment (0) | Author: Frank-Peter

Which countries are most interested in Powershell? Surprise :)

Wednesday, 10. February 2010 9:46

During my recent investigation, I wanted to be sure that Powershell is really getting adopted and that it grows every year…

You can either try to get some results from companies like Gartner, but I usually don’t trust them too much. For me, best resource is of course Google ;)

According to Google, we can see that interest in powershell is still growing:

Posh

I was also curious which countries are mostly interested in Powershell. Did you expect to see here U.S., UK, Germany or similar countries?

1. Russian federation

2. Norway

3. Czech republic :)

If you want to see report yourself, simply follow this link.

Martin Zugec

Category:General, Internet, PowerShell, PowerShell News | Comment (0) | Author: Martin Zugec

grep for PowerShell

Tuesday, 2. February 2010 23:07

Hello again. This time I will share a small function that resides in my PowerShell profile script: grep. What is grep? grep is a text search utility originally written for Unix. The command name is an abbreviation for “global regular expression print”. The original grep – and my PowerShell grep function as well – searches files for lines matching a given regular expression and displays the matches in standard output.

Here comes the ready for use function…

function grep (
    $File = $(throw "Empty value for the File parameter."),
    $Pattern = $(throw "Empty value for the Pattern parameter."),
    [switch]$Recurse
) {
    if ($Recurse) {
        $Files = @(Get-ChildItem $File -Recurse)
    } else {
        $Files = @(Get-ChildItem $File)
    }
    if ($Files.Count -eq 0) {
        Write-Host "File(s) not found - $File"; return $null
    }
    $Results = $Files | Select-String -Pattern $Pattern
    if (!$Results) {
        Write-Host "No matches found in $File"; return $null
    }
    $Results | Format-List FileName,LineNumber,Line
}

Actually the grep function simplifies the usage of a command line like below:

PS C:\> gci c:\windows\windowsupdate*.log | Select-String "2009-12" | fl FileName,LineNumber,Line

Using grep you just need to type this:

PS C:\> grep -File C:\Windows\WindowsUpdate*.log -Pattern "2009-12"

Ah, almost I forgot to mention that the Select-String cmdlet is PowerShell’s grep.

Category:General, PowerShell | Comments (1) | Author: Frank-Peter