Archive

Posts Tagged ‘powershell’

Powershell: Get Manager name from Active Directory

I want to write about another quick post before I sign off today. One of my friend asked me how to get Manager of a user from active directory using powershell. He seem to have tried ActiveDirectory module to get this information but it never returned any data.

So, I this post I want to provide quick one-liners using Quest AD cmdlets and built-in activedirectory cmdlets which returns the Manager attribute information from active directory.

Using Quest AD CMDlets:

Get-QADUser -Id User1 | select Manager

Using ActiveDirectory Module:

You need to note one thing when you are using ActiveDirectory module. Most cmdlets in this module never returns all properties by default. You need to explicitly ask for attribute when using the cmdlets in this module.

So, Get-ADUser -Id User1 | select Manager will not work as there won’t be any parameter called Manager in default output. You should use something like below to get the data.

Get-ADUser -Id User1 -Properties Manager | select Manager            

OR            

Get-ADUser -Id User1 -Properties * | select Manager

Hope this helps…

 

Powershell: How to get all the AD groups current user belongs

This simple script will help you to get the list of ALL(both direct and indirect groups) the current user belongs. Generally we use Quest cmdlets to get this direct and indirect group membership information but this script uses buil-in dotnet method which is available on all computers if you have dotnet installed. So, no need of external dependencies like Quest AD cmdlets.

Function Get-AllUserGroups {
[cmdletbinding()]
param()
$Groups = [System.Security.Principal.WindowsIdentity]::GetCurrent().Groups
foreach ($Group in $Groups) {
  $GroupSID = $Group.Value
  $GroupName = New-Object System.Security.Principal.SecurityIdentifier($GroupSID)
  $GroupDisplayName = $GroupName.Translate([System.Security.Principal.NTAccount])
  $GroupDisplayName
  }
}

I still haven’t figured out a way to get the same information for a given user(not currently logged on user) using dotnet methods. Please let me know if you are aware of any such procedure.

[UPDATE]

Shay Levy has provided a way to do get the all groups of a given user account(see comments section). I am updating it here for everyone’s quick reference.

#curtsy : Shay Levy             

$userName = ‘sitaram’
Add-Type -AssemblyName System.DirectoryServices.AccountManagement
$ct = [System.DirectoryServices.AccountManagement.ContextType]::Domain
$user = [System.DirectoryServices.AccountManagement.Principal]::FindByIdentity($ct,$userName)
$user.GetGroups() #gets all user groups (direct)
$user.GetAuthorizationGroups() #gets all user groups including nested groups (indirect)

Hope this helps…

Powershell: Most useful powershell commands for XenApp environment

This is continuation to my previous post. I want to add more commands that System Administrator require to manage XenApp environment using powershell. Below are some of them. I will extend the list as and when I find something.

Get the list of Users currently using a published XenApp Application:

Get-XASession -BrowserName notepad | select AccountName

Get the computer(or client) name from where a XenApp Application is launched

Get-XASession -BrowerName notepad | select ClientName, AccountName

Logoff a user(user1) session who opened “MS Word” application in XenApp:

(Get-XASession -BrowserName “MS Word” -ServerName XenAPP1 | ? {$_.AccountName -match “User1″ }).SessionID | Stop-XASession

Get all published XenApp applications on a Server

Get-XAApplication -ServerName XenApp1 | select DisplayName

Get all Desktops published in XenApp environment

Get-XAApplication | ? {$_.ApplicationType -eq “ServerDesktop” } | select DisplayName

Get the users or groups who has permission to a published application:

Get-XAAccount -BrowserName App1

How to get the list of processes running in a given XenApp session on server:

Get-XASessionProecss -ServerName XenApp1 -Sessionid 10

 Rename a published XenApp Application (or change displayname of XenApp Application):

Get-XAApplication -BrowserName “My Notepad” | Rename-XAApplication -NewDisplayName “My Notepad – OLD”

Change the description of a XenApp application:

Get-XAApplication -BrowserName “My Notepad – OLD” | Set-XAApplication -Description “This is going to retire”

 

Powershell: How to get list of Citrix XenApp Servers publishing a given Application

Today I got a requirement to find out the list of Citrix XenApp Servers where a application is published. All I have is the name of the published application. Though I have been using powershell for a while now, I never tried it in Citrix environment. I took me some time to figure out the Add-Ins, modules required for querying the XenApp6 environment.  After familiarizing with XenApp powershell commands, I realized there is lot I can do with it in XenApp environment. And it is faster than GUI.

So, here is the script I am talking about which takes application name as parameter and displays the XenApp servers where it is published, Accounts that have access to it, path of the application, Type of the application(streamed/serverInstalled), Executable path and many more details.

Note that you need to download and install Citrix XenApp 6 Powershell SDK to get the required SnapIns. This is not required if you are running the script from a XenApp server since it already contains the required Powershell SDK installation.

function Get-CitrixPublishedApplicationDetails {
[cmdletbinding()]
param(
[string]$AppName
)            

Add-PsSnapIn Citrix*
Get-XAApplicationReport -BrowserName $AppName | Select DisplayName, ServerNames, Accounts, ApplicationType, ClientFolder, CommandlineExecutable            

}

Usage:

Get-CitrixPublishedApplicationDetails -AppName Notepad

Hope this helps…

[update]

There is another way available as well which returns the list of XenApp Servers on which a given application is hosted.

Get-XAServer -BrowserName Notepad | select ServerName

 

Powershell: Unexpected attribute ‘cmdletbinding’(ParentContainsErrorRecordException)

I get the below error sometimes while working with powershell scripts. Every time I end up spending some efforts to recollect what I have done previously to fix this. This time I decided to document it for my quick reference and for other powershell users.

ERROR Message:

Unexpected attribute ‘cmdletbinding’.
At line:24 char:15
+ [cmdletbinding <<<< ()] + CategoryInfo : ParserError: (:) [], ParentContainsErrorRecordException + FullyQualifiedErrorId : UnexpectedAttribute

When we will get this error?

This error we will generally observe when copy pasting a function from script to powershell console for quick execution. It is also quite possible that you might get this error while running some script or importing a function.

What are the causes for this error?

Mainly there are two cases where you will get this error.

Missing of param declaration:

We declare [cmdletbinding()] in a function or script but may miss to declare parameters after that. It is possible that your script/function doesn’t requires any parameters but you still need to declare it like param ( ). Otherwise you will get the above error.

So, it is general thump rule that [cmdletbinding()] should follow param() like below.

function foo-bar {
[cmdletbinding()]
param (
)
...
...
...
}

A new line between [cmdletbinding()] and param declaration:

Just try copy pasting the below code into a powershell window and let me know what happens. You will definitely observe the above given error. This is because of the new line between [cmdletbinding()] and param declaration. Now remove the new line and try again. It should go well.

function foo-bar {
[cmdletbinding()]            

param (
)
...
...
...
}

Note that above is true while copy pasting the code into powershell window. If you have this space in a script and you are executing the script from powershell window, then you may not notice this.

Hope this helps… Happy learning…

 

Powershell: Get scheduled tasks list from Windows 7/2008 computers

The below script helps you to query scheduled tasks from remote computer which is running with Windows 7/Windows 2008  or above. You can use this script to query multiple computers to get all the scheduled tasks. You can also query the computer by using a scheduled task name as well.

<#

    .Synopsis
        Get the list of scheduled Tasks from Windows 7 or Windows 2008 computers
        
    .Description
        This script displays all the scheduled tasks available in a windows 7 or windows 2008 computer.
 
    .Parameter ComputerName    
        Computer Name(s) from which you want to get the scheduled tasks information. If this
        parameter is not used, the the script gets the scheduled tasks list from local computer.
        
    .Parameter TaskName    
        Name of the scheduled task that you want to query. This is a optional parameter.
        
    .Example 1
        Get-ScheduledTask.ps1 -ComputerName Comp1, Comp2
        Get the scheduled tasks information from listed computers.
    .Example 2
        Get-ScheduledTask.ps1 -ComputerName Comp1 -TaskName "Calibration Loader"
        
        Get the details of given task from Comp1.
        
    .Notes
        NAME:      Get-ScheduledTask.ps1
        AUTHOR:    Sitaram Pamarthi
        WEBSITE:   http://techibee.com

#>
[cmdletbinding()]
param (
 [parameter(ValueFromPipeline=$true,ValueFromPipelineByPropertyName=$true)]
 [string[]] $ComputerName = $env:computername,
 [string] $TaskName
)
#function to get all scheduled task folder details.
function Get-TaskSubFolders {
[cmdletbinding()]
param (
 $FolderRef
)
$ArrFolders = @()
$folders = $folderRef.getfolders(1)
if($folders) {
 foreach ($folder in $folders) {
  $ArrFolders = $ArrFolders + $folder
  if($folder.getfolders(1)) {
   Get-TaskSubFolders -FolderRef $folder
  }
 }
}
return $ArrFolders
}            

#MAIN            

foreach ($Computer in $ComputerName) {
 $SchService = New-Object -ComObject Schedule.Service
 $SchService.Connect()
 $Rootfolder = $SchService.GetFolder("\")
 $folders = Get-Tasksubfolders -FolderRef $RootFolder
 foreach($Folder in $folders) {
  $Tasks = $folder.gettasks(1)
  foreach($Task in $Tasks) {
   $OutputObj = New-Object -TypeName PSobject
   $OutputObj | Add-Member -MemberType NoteProperty -Name ComputerName -Value $Computer
   $OutputObj | Add-Member -MemberType NoteProperty -Name TaskName -Value $Task.Name
   $OutputObj | Add-Member -MemberType NoteProperty -Name TaskFolder -Value $Folder.path
   $OutputObj | Add-Member -MemberType NoteProperty -Name IsEnabled -Value $task.enabled
   $OutputObj | Add-Member -MemberType NoteProperty -Name LastRunTime -Value $task.LastRunTime
   $OutputObj | Add-Member -MemberType NoteProperty -Name NextRunTime -Value $task.NextRunTime
   if($TaskName) {
    if($Task.Name -eq $TaskName) {
     $OutputObj
    }
   } else {
     $OutputObj
   }
  }            

 }            

}

Output:

Feel Free to post here if you have any trouble in using this script. Happy to help!!!

 

Powershell: Split a string by white space(s)

While writing a script today, I faced a situation where I have a string like “This is my       test                string”. As you have already noticed there are more than one spaces at different places in the string. All I need to do is eliminate all spaces and fit the words alone into a array.

Since this is a split by white space operation, I tried below and got bit surprised with the output.

$string = "This is my test string"
$string.split(" ") 

Output:

The output is array which is containing the words plus some spaces in middle. This is not what I expected. After some struggle, I made it to work by using -Split.

Now the working code is…

$string = "This is my test string"
$array = $string -split "\s+"
$array

 

Output:

 

Hope this little tip helps. Visit to http://www.powershelladmin.com/wiki/Powershell_split_operator for more examples about using -Split.

[Update]:

The usage for -split is very simple and I believe this is a best suit for simple requirements like the one I showed you above. But if you have something more complex, then you may want to explore the usage of [regedit]::Split() dotnet method.

Why am I getting powershell output in @{parametername=parametervalue}.parametername

One of my friend is trying to get computers list from active directory using below code. All he want is names of the computers in a array.

$TestPcNames = Get-QAComptuer -Id TEST* | select Name
$TestPCNames | % { write-host "$_.Name" }

There is nothing really wrong with the above code. All it contains is computer names but in object format. For that reason when he is trying to print the computer name, he is getting something like @{Name=TESTPC1}.Name

There he is stuck and now don’t know how to get list of computer accounts(in string format) in a array. This is very basic problem that every system administrator will face when trying to get their hands wet with powershell. I have also gone through this a couple of years back when I am studying ABCs of powershell.

The solution for this is very easy. First get the things printed correctly. You can use either of below one liners for that.

$TestPCNames | % { write-host "$($_.Name)" }         

$TestPCNames | % { $_.Name }

Once you seen them printed as string array(you will noted there won’t be any column header with work “Name”), all you need to do is assign the output to a variable.

$CompArray = $TestPCNames | % { write-host "$($_.Name)" }
$CompArray = $TestPCNames | % { $_.Name }

Now $CompArray contains the list of computers. Hope this little tip helps…

 

Categories: PowerShell Tags: ,

Powershell: Script to take a screenshot of your desktop

“Could you please send me a screenshot of what you are seeing?”. This is a frequent question we system administrators ask the end users. So, I just got a thought why I can’t take a screenshot of desktop using powershell so that I can incorporate this to my other automations if needed. That is when this script born.

When searched in google for this, I found a stackoverflow thread(http://stackoverflow.com/questions/2969321/how-can-i-do-a-screen-capture-in-windows-powershell) where different approaches are described to take a screenshot using powershell. I could make only one method working and the other is having problems. However, the working method has a limitation as I need to explicitly pass the width and height of the screen that has to be captured. If I am interested on whole screen, from where I can get these coordinates? My previous post(Get-ScreenResolution) came handy here. I read the screen resolution details using Get-Screenresolution.ps1 script and passed the output to the function I found in stackoverflow. Now it is working exactly the way I want.

For general usage, I made few more modifications to the code to allow explicitly pass the width and height details using -Width and -Height parameters. There is also another parameter called -FileName using which you can provide the name you want for the screenshot. Don’t provide a file extension here. The script saves the output in PNG format by default. If -FileName parameter is not specified you can see the output in %temp% with Screenshot.png name.

Get-ScreenShot.ps1

[cmdletbinding()]
param(
  [string]$Width,
  [string]$Height,
  [String]$FileName = "Screenshot"            

)            

#Function to take screenshot. This function takes the width and height of the screen that has
#to be captured            

function Take-Screenshot{
[cmdletbinding()]
param(
 [Drawing.Rectangle]$bounds,
 [string]$path
)
   $bmp = New-Object Drawing.Bitmap $bounds.width, $bounds.height
   $graphics = [Drawing.Graphics]::FromImage($bmp)
   $graphics.CopyFromScreen($bounds.Location, [Drawing.Point]::Empty, $bounds.size)
   $bmp.Save($path)
   $graphics.Dispose()
   $bmp.Dispose()
}            

#Function to get the primary monitor resolution.
#This code is sourced from 
# http://techibee.com/powershell/powershell-script-to-get-desktop-screen-resolution/1615            

function Get-ScreenResolution {
 $Screens = [system.windows.forms.screen]::AllScreens
 foreach ($Screen in $Screens) {
  $DeviceName = $Screen.DeviceName
  $Width  = $Screen.Bounds.Width
  $Height  = $Screen.Bounds.Height
  $IsPrimary = $Screen.Primary
  $OutputObj = New-Object -TypeName PSobject
  $OutputObj | Add-Member -MemberType NoteProperty -Name DeviceName -Value $DeviceName
  $OutputObj | Add-Member -MemberType NoteProperty -Name Width -Value $Width
  $OutputObj | Add-Member -MemberType NoteProperty -Name Height -Value $Height
  $OutputObj | Add-Member -MemberType NoteProperty -Name IsPrimaryMonitor -Value $IsPrimary
  $OutputObj
 }
}            

#Main script begins            

#By default captured screenshot will be saved in %temp% folder
#You can override it here if you want
$Filepath = join-path $env:temp $FileName            

[void] [Reflection.Assembly]::LoadWithPartialName("System.Windows.Forms")
[void] [Reflection.Assembly]::LoadWithPartialName("System.Drawing")            

if(!($width -and $height)) {            

 $screen = Get-ScreenResolution | ? {$_.IsPrimaryMonitor -eq $true}
 $Width = $screen.Width
 $Height = $screen.height
}            

$bounds = [Drawing.Rectangle]::FromLTRB(0, 0, $Screen.Width, $Screen.Height)            

Take-Screenshot -Bounds $bounds -Path "$Filepath.png"
#Now you have the screenshot

Usage:

Simple, just run the script from powershell window, you will see the output in %temp%\screenshot.png

Hope this helps… feedback welcome.

 

 

Powershell: Write-EventLog Error “Write-EventLog : The source name XXX does not exist on computer

If you are using Write-EventLog to write any new events to event log, it is possible that you might see below error.

Write-EventLog : The source name “XXX” does not exist on computer “localhost”.

I am into similar situation today. What I was doing is trying to write a new event in to Application event log with a Event Source that is not already exists in the computer where I am trying. So the error message makes sense. It is saying the source I am trying to use, XXX doesn’t exists. So, how should get this added to list of available event sources in the computer so that it won’t through the error message again.

After little bit of googling, I found the below method promising.

New-EventLog -LogName Application -Source “XXX”

This command creates a new event source in Application Event log with the name XXX. All I need to do is just use this command once and try the write-EventLog cmdlet with the same source name(XXX). It worked this time.

Hope this little trick helps you…

[Update]

There are some dotnet ways available as well to see if a given source is available in EventLog and create one if needed.

To check if the source exists:

PS C:\> [system.diagnostics.eventlog]::SourceExists(“XXX”)
False
PS C:\>

To create a new source entry in event log:

[system.diagnostics.EventLog]::CreateEventSource(“XXX”, “Application”)