Recently I started listening to a podcast that focuses on PowerShell and it inspired me to learn more about it. PowerShell is a Bash-like environment that will play a huge part in new and future Microsoft software and sofware from other vendors. Currently VMWare and Citrix are both making there products PowerShell aware and Exchange 2007 and Windows Core will heavily rely upon PowerShell.
Being a fan of the commandline I really wanted to learn more about PowerShell and from having no programming or scripting knowledge heres what I picked up in the past 2 days.
Mostly I was interested in how it might be useful for Systems Administration and getting right down into the guts of a system.
Tools
- PowerShell
- Snap-ins
- Quest.ActiveRoles.ADManagement
Powershell Basics
A list of the available commands can be seen by typing get-command at the powershell prompt.
More information and exampes can be found about each command by typing get-help get-command for example.
PowerShell uses tab completion, and also has the beefit of aliases. The aliases can be listed by typing get-alias. Once you are familier with aliases these can save a whole load of typing, for example:
get-process -name vm* | format-Table
Becomes
gps -name vm* | ft

In the example above, you can see that I have piped the output of get-process into the format-table commandlet. Piping is very common in PowerShell and it will allow you to create som useful one-liners.
One other word on tab completion, if I wanted to know what options were available for say the get-content commandlet i would type get-content - and then press tab to cycle through the options. From there I would see an option called wait. Using this I could run a command very similar to tail -f in Linux. For example:
get-content -wait logfile.txt
This will display the logfile in the current directory and if any new events occur I will see them straight away. Cool!
Below are some really useful one-liners that I have found that will be useful in these situations. I'll list the basic commands that can be run, and then i'll expand upon those commands to help explain how the commands may be run on remote systems, how the output might be filtered and redirected to a file rather than the screen.
Processes
To start with I'm simply going to retrieve running processes.
Get-Process

Now i could filter the output by a particular service by specifying the name.
Get-Process -Name firefox

And taking it a step further I can display the output as a list rather than a table.
Get-Process -Name firefox | Format-list

Now I might also want to see what other fields are available (easier to do this one as a list).
Get-Process -Name firefox | Format-List -Property *

And once I have identified some useful fields I'll focus on just those.
Get-Process -Name firefox | Format-List -Property ProcessName,FileVersion

Once i have narrowed down what I want I can output the results to either screen, file or printer using the commands below.
Get-Process | Out-Host -Paging | Format-List
Get-Process | Out-File -FilePath C:\temp\processlist.txt
Get-Command | Out-File -FilePath c:\temp\output.txt -Width 2147483647
Get-Command Get-Command | Out-Printer -Name "Microsoft Office Document Image Writer"
I might also want to list the highest load processes. For this I pipe the results of get-process into a where-object variable.
gps | where-object {$_.WorkingSet -gt 10000000}
WMI in PowerShell
I can also do get same info using WMI classes as can be seen below. Here I look at processes on a remote host and filter the output.
I can get a full list of WMI classes available by using this command
Get-WmiObject -List

As can be seen from the output there are hundreds of WMI objects that can be queried.
And here I query the processes using WMI
Get-WmiObject -Class Win32_process -Namespace root/cimv2 -ComputerName .

And on a remote host.
Get-WmiObject -List -ComputerName 10.50.1.1
And then i might filter the output using:
Get-WmiObject -Class Win32_process -Namespace root/cimv2 -ComputerName 10.101.1.2 | format-list name, commandline
After querying the WMI classes available I can enumerate quite alot of information as can be seen from the commands below.
Get-wmiobject –class win32_service | select-object [a-z]* | export-csv c:\service.csv
Get-wmiobject -class win32_logicaldisk

Get-WmiObject -Class Win32_process -Namespace root/cimv2 -ComputerName 10.101.1.1
Get-WmiObject -Class Win32_OperatingSystem -Namespace root/cimv2 -ComputerName .
Get-WmiObject -Class Win32_OperatingSystem -Namespace root/cimv2 -ComputerName 10.201.1.1
Get-WmiObject -Class Win32_PrinterSetting -Namespace root/cimv2 -ComputerName 10.201.1.1
Get-WmiObject -Class Win32_userAccount -Namespace root/cimv2 -ComputerName 10.201.1.1
Get-WmiObject -Class Win32_useraccount -Namespace root/cimv2 -ComputerName 10.201.1.1 | format-list accounttype, name
Eventlogs in PowerShell
In the examples below I will demonstrate how to display an eventlog in PowerShell and then filter the results.
Get-eventlog -logname system

The results from the above query will likely be overwhelming. I'll use a few comands to cut down on the data.
get-eventlog -newest 10 -logname system

I can also use the use export to csv function.
Get-eventog -logname system | epcsv c:\system-events.csv
Or to filter or exclude on just certain events.
get-eventlog -newest 100 -logname system | where { $_.eventid -match "7036"}
get-eventlog -newest 100 -logname system | where { $_.eventid -notmatch "7036"}
get-eventlog -newest 100 -logname system | where {$_.entrytype -match "warning"}

Active Directory
With the free Active Directory add-in from Quest you can query many properties on objects within AD. Below are some examples.
get-qaduser -company * -sl 500 | select company | sort -property company | Get-Unique -asstring
This query would look at the company field in a users AD profile and return no more than 500 unique results. obviously this could be applied to any field.
To focus on just one AD user called John Smith I might use:
get-qaduser "John Smith"
To see all the AD fields available I would use the following command:
get-qaduser "John Smith" | select *
or for very verbose output try:
get-qaduser "John Smith" -includeallproperties | select *
Terminal Services
Now this I found very useful as I was always unable to query AD for a users terminal services path using traditional tools. But here I am able to filter just on those fields.
get-qaduser "John Smith" | format-list Tsp*
or o use wildards:
get-qaduser "John*" | Format-table name, tsp*
and then to output it to a file I might use:
get-qaduser "John*" | Format-table name, tsp* > c:\term-serv-prof.csv
Disks Information
A really important part of my job is to make sure there is adequate diskspace on many servers across many locations. I developed a one-liner at the bottom of this section that will query a list of servers and get the disk information for me.
I start by looking at my local disk to get familier with the commands.
Get-WmiObject -Class Win32_LogicalDisk -Filter "DriveType=3" -ComputerName .

To see all the disk properties available I use:
Get-WmiObject -Class Win32_LogicalDisk -Filter "DriveType=3" -ComputerName . | Select-Object -Property *
Before I continue, if i want to learn more about the properties I can pipe the WMI class into get-member. get-member is really useful and will tell me loads about any properties of the commands.

From here I can see what the methods are (things you can do) and what the properties are (things you can query).
Now Focus on just the ones I need.
Gwmi win32_logicaldisk -Filter "DriveType=3" -comp . | Select-Object -Property SystemName,Caption,VolumeName,Name,FreeSpace | format-table

Ah, it's slightly anoying that all my output didn't fit on the screen. after looking at the help (get-help format-table -full) I find there is an auto size switch.

Thats better.
So now I try using a list of servers to see how that goes. My list is just the server names in a text file. And I use the alias for Get-WmiObject.
Gwmi win32_logicaldisk –comp (gc c:\servers.txt)
That went well, so i build on it to examine them for disknames, partition, total size and free space and out put the results to a new file (Server-Disk.csv)
Gwmi win32_logicaldisk -Filter "DriveType=3" -comp (gc c:\servers.txt) | format-table -property SystemName, Caption, VolumeName, Size, Freespace | out-file -filepath c:\Server-Disk.csv
But thats not good enough, I now need to convert the disk sizes to GB. I try it first on my local drives.
Gwmi win32_logicaldisk -Filter "DriveType=3" -comp . | Select-Object -Property SystemName,Caption,VolumeName,Name,FreeSpace | ForEach-Object -Process {$_.FreeSpace = ($_.FreeSpace)/1024/1024/1024; $_} | format-table -auto

Cool, and now for the servers.
Gwmi win32_logicaldisk -Filter "DriveType=3" -comp (gc c:\servers.txt) | Select-Object -Property SystemName,Caption,VolumeName,Name,Size,FreeSpace | ForEach-Object -Process {$_.FreeSpace = ($_.FreeSpace)/1024/1024/1024; $_} | format-table | out-file -filepath c:\Disk-GB.csv
Now after testing this I found the command Export-CSV, I could have used that instead of out-file -filepath which may have been slightly better for formating. But I need to test that.
Networking
Below are a few commands that return details on the network card configuration.
Get-WmiObject -Class Win32_NetworkAdapterConfiguration -Filter IPEnabled=TRUE -ComputerName . | Format-list -Property *

Get-WmiObject -Class Win32_NetworkAdapterConfiguration -Filter IPEnabled=TRUE -ComputerName . | Format-Table -Property IPAddress
Get-WmiObject -Class Win32_NetworkAdapterConfiguration -Filter "IPEnabled=true and DHCPEnabled=true" -ComputerName .
This ones interesting, I am able to ping a remote host from another remote host.
Get-WmiObject -Class Win32_PingStatus -Filter "Address='10.50.1.1'" -ComputerName 10.50.1.2 | Format-Table -Property Address,ResponseTime,StatusCode -Autosize
Or I can ping a list of hosts from my PC.
"www.yahoo.com","www.bbc.co.uk" | ForEach-Object -Process {Get-WmiObject -Class Win32_PingStatus -Filter ("Address='" + $_ + "'") -ComputerName .} | Select-Object -Property Address,ResponseTime,StatusCode | format-table -auto

The same thing again but to local addresses in the 10.50.1.x range.
1..10| ForEach-Object -Process {Get-WmiObject -Class Win32_PingStatus -Filter ("Address='10.50.1." + $_ + "'") -ComputerName .} | Select-Object -Property Address,ResponseTime,StatusCode
To Create a share using PowerShell
(Get-WmiObject -List -ComputerName . | Where-Object -FilterScript {$_.Name -eq "Win32_Share"}).Create("C:\temp","NewShare",0,25,"temp folder share")
Registry
Now I'm a big fan of looking at the registry and PowerShell is not too shabby for using as a tool to do this.
Here are some basic queries.
Get-ItemProperty -Path Registry::HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows\CurrentVersion\Run

Get-ItemProperty -Path Registry::'HKEY_CURRENT_USER\Software\Microsoft\Internet Explorer\TypedURLs'
And now I use PowerShell to create a new key.
New-ItemProperty -Path HKLM:\SOFTWARE\Microsoft\Windows\CurrentVersion\Run -Name Test -PropertyType String -Value C:\Windows
And delete the key.
Remove-ItemProperty -Path HKLM:\SOFTWARE\Microsoft\Windows\CurrentVersion -Name Test
One thing that I havent been able to get as a one-liner just yet is the modification of remote registries. But I am working on it. Also XP allowed me to create registry entries but Vista did not.
Links
Fisnally, below arer some useful one-line that I thought i would include as it's handy to refer back to these at some stage.
Get-WmiObject -Class Win32_LogonSession -ComputerName . | Select-Object -Property *
Get-WmiObject -Class Win32_ComputerSystem -Property UserName -ComputerName .
Get-WmiObject -Class Win32_LocalTime -ComputerName . | Select-Object -Property [a-z]*
Examples of filters:
Get-WmiObject -Class Win32_SystemDriver | Where-Object -FilterScript {$_.name -eq "acpi"} | Format-list -property *
Get-WmiObject -Class Win32_SystemDriver | Where-Object -FilterScript {$_.State -eq "Running"} | Where-Object -FilterScript {$_.StartMode -eq "Manual"}
Getting the time from servers and outputting the results to a new file:
Get-Content servers.txt | %{$x = net time \\$_; $x[0];If($x[2].contains(”Local”)){$x[2]}} | Add-Content Servertime.txt
Listing open sessions on a remote server:
Get-TerminalSession -ComputerName server123 | format-list -property client, state, username
Searching through a file and outputting content to a new file:
Get-Content file.txt | select-string -pattern "admin*" | set-content admin-users.txt
Searching through a directory for content in a file:
Select-String -path "C:\Users\Lee\*.*" "admin"
To create a variable and then search it:
$wmi = get-wmi-object -list
$wmi | select-string -pattern "network" , "security"
Terminal Services
Now this I found very useful as I was always unable to query AD for a users terminal services path using traditional tools. But here I am able to filter just on those fields.
get-qaduser "John Smith" | format-list Tsp*
or o use wildards:
get-qaduser "John*" | Format-table name, tsp*
and then to output it to a file I might use:
get-qaduser "John*" | Format-table name, tsp* > c:\term-serv-prof.csv
Disks Information
A really important part of my job is to make sure there is adequate diskspace on many servers across many locations. I developed a one-liner at the bottom of this section that will query a list of servers and get the disk information for me.
I start by looking at my local disk to get familier with the commands.
Get-WmiObject -Class Win32_LogicalDisk -Filter "DriveType=3" -ComputerName .

To see all the disk properties available I use:
Get-WmiObject -Class Win32_LogicalDisk -Filter "DriveType=3" -ComputerName . | Select-Object -Property *
Before I continue, if i want to learn more about the properties I can pipe the WMI class into get-member. get-member is really useful and will tell me loads about any properties of the commands.

From here I can see what the methods are (things you can do) and what the properties are (things you can query).
Now Focus on just the ones I need.
Gwmi win32_logicaldisk -Filter "DriveType=3" -comp . | Select-Object -Property SystemName,Caption,VolumeName,Name,FreeSpace | format-table

Ah, it's slightly anoying that all my output didn't fit on the screen. after looking at the help (get-help format-table -full) I find there is an auto size switch.

Thats better.
So now I try using a list of servers to see how that goes. My list is just the server names in a text file. And I use the alias for Get-WmiObject.
Gwmi win32_logicaldisk –comp (gc c:\servers.txt)
That went well, so i build on it to examine them for disknames, partition, total size and free space and out put the results to a new file (Server-Disk.csv)
Gwmi win32_logicaldisk -Filter "DriveType=3" -comp (gc c:\servers.txt) | format-table -property SystemName, Caption, VolumeName, Size, Freespace | out-file -filepath c:\Server-Disk.csv
But thats not good enough, I now need to convert the disk sizes to GB. I try it first on my local drives.
Gwmi win32_logicaldisk -Filter "DriveType=3" -comp . | Select-Object -Property SystemName,Caption,VolumeName,Name,FreeSpace | ForEach-Object -Process {$_.FreeSpace = ($_.FreeSpace)/1024/1024/1024; $_} | format-table -auto

Cool, and now for the servers.
Gwmi win32_logicaldisk -Filter "DriveType=3" -comp (gc c:\servers.txt) | Select-Object -Property SystemName,Caption,VolumeName,Name,Size,FreeSpace | ForEach-Object -Process {$_.FreeSpace = ($_.FreeSpace)/1024/1024/1024; $_} | format-table | out-file -filepath c:\Disk-GB.csv
Now after testing this I found the command Export-CSV, I could have used that instead of out-file -filepath which may have been slightly better for formating. But I need to test that.
Networking
Below are a few commands that return details on the network card configuration.
Get-WmiObject -Class Win32_NetworkAdapterConfiguration -Filter IPEnabled=TRUE -ComputerName . | Format-list -Property *

Get-WmiObject -Class Win32_NetworkAdapterConfiguration -Filter IPEnabled=TRUE -ComputerName . | Format-Table -Property IPAddress
Get-WmiObject -Class Win32_NetworkAdapterConfiguration -Filter "IPEnabled=true and DHCPEnabled=true" -ComputerName .
This ones interesting, I am able to ping a remote host from another remote host.
Get-WmiObject -Class Win32_PingStatus -Filter "Address='10.50.1.1'" -ComputerName 10.50.1.2 | Format-Table -Property Address,ResponseTime,StatusCode -Autosize
Or I can ping a list of hosts from my PC.
"www.yahoo.com","www.bbc.co.uk" | ForEach-Object -Process {Get-WmiObject -Class Win32_PingStatus -Filter ("Address='" + $_ + "'") -ComputerName .} | Select-Object -Property Address,ResponseTime,StatusCode | format-table -auto

The same thing again but to local addresses in the 10.50.1.x range.
1..10| ForEach-Object -Process {Get-WmiObject -Class Win32_PingStatus -Filter ("Address='10.50.1." + $_ + "'") -ComputerName .} | Select-Object -Property Address,ResponseTime,StatusCode
To Create a share using PowerShell
(Get-WmiObject -List -ComputerName . | Where-Object -FilterScript {$_.Name -eq "Win32_Share"}).Create("C:\temp","NewShare",0,25,"temp folder share")
Registry
Now I'm a big fan of looking at the registry and PowerShell is not too shabby for using as a tool to do this.
Here are some basic queries.
Get-ItemProperty -Path Registry::HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows\CurrentVersion\Run

Get-ItemProperty -Path Registry::'HKEY_CURRENT_USER\Software\Microsoft\Internet Explorer\TypedURLs'
And now I use PowerShell to create a new key.
New-ItemProperty -Path HKLM:\SOFTWARE\Microsoft\Windows\CurrentVersion\Run -Name Test -PropertyType String -Value C:\Windows
And delete the key.
Remove-ItemProperty -Path HKLM:\SOFTWARE\Microsoft\Windows\CurrentVersion -Name Test
One thing that I havent been able to get as a one-liner just yet is the modification of remote registries. But I am working on it. Also XP allowed me to create registry entries but Vista did not.
Links
Fisnally, below arer some useful one-line that I thought i would include as it's handy to refer back to these at some stage.
Get-WmiObject -Class Win32_LogonSession -ComputerName . | Select-Object -Property *
Get-WmiObject -Class Win32_ComputerSystem -Property UserName -ComputerName .
Get-WmiObject -Class Win32_LocalTime -ComputerName . | Select-Object -Property [a-z]*
Examples of filters:
Get-WmiObject -Class Win32_SystemDriver | Where-Object -FilterScript {$_.name -eq "acpi"} | Format-list -property *
Get-WmiObject -Class Win32_SystemDriver | Where-Object -FilterScript {$_.State -eq "Running"} | Where-Object -FilterScript {$_.StartMode -eq "Manual"}
Getting the time from servers and outputting the results to a new file:
Get-Content servers.txt | %{$x = net time \\$_; $x[0];If($x[2].contains(”Local”)){$x[2]}} | Add-Content Servertime.txt
Listing open sessions on a remote server:
Get-TerminalSession -ComputerName server123 | format-list -property client, state, username
Searching through a file and outputting content to a new file:
Get-Content file.txt | select-string -pattern "admin*" | set-content admin-users.txt
Searching through a directory for content in a file:
Select-String -path "C:\Users\Lee\*.*" "admin"
To create a variable and then search it:
$wmi = get-wmi-object -list
$wmi | select-string -pattern "network" , "security"
Finally, thank you to all the guys from the PowerShell Community Forums who have helped me get started on Powershell.

7 comments:
Thanks Syn
Question, its seems like there unlimited ways the company network can upload my files, I view these actions on XML files, is it true?
If so, how do I put a stop to it?
M
NO AIM please
Your blog is so good.I'm your fan..goahead..You can access my blogs.We will share ideas together.
Hey thanks man!
hi,You are welcome!.Dear,Can you suggest some websites,which can help me in programming-level with powershell.If you have any blog or website links,please reply.I will expect the reply in your blog comments...
hi,
Can you help me debug this powershell script.There are some erorrs and i cannot fix it.
if(!$args)
{
write-host -foregroundcolor green
$args= `localhost`
}
if($args -eq "?")
{ "ReportDiskdriveconfiguration.ps1
"
}
gwmi win32_diskdrive -computer $args
Blog, i'm not too sure what it is your trying to do.
I would suggest posting to the Powershell Community forums. You'll get a lot more people looking at the script and I can guarantee that they are alot better scripters than I am.
Syn
No need.I fixed the error.Thank you.
Post a Comment