Posts Tagged PowerShell

Send a Tweet from PowerShell

I was reading Shay’s article on how to send direct messages on twitter using PowerShell when I couldn’t resist but find a way to send normal tweets from PowerShell. While trying to do that, I also incorporated security so that your transmission is secure and so is your input. Here’s the code:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
function Send-Tweet($Message,$UserName)
{
   if ($Message -eq $null) {$Message = Read-Host "Enter your tweet"}
   if ($Username -eq $null) {$Username = read-host "Enter your twitter username"}
   if ($Password -eq $null)
   {
	$Password = read-host -assecurestring "Enter your twitter password"
	$marshal = [Runtime.InteropServices.Marshal]
	$Password = $marshal::PtrToStringAuto($marshal::SecureStringToBSTR($Password))
   }
   $url="https://twitter.com/statuses/update.xml?status=$Message"
   $request = [System.Net.WebRequest]::Create($url)
   $request.credentials= New-Object System.Net.NetworkCredential($UserName,$Password)
   $request.method= "POST"
   $request.contentType = "application/x-www-form-urlencoded"
   $request.GetResponse().statusCode # return the status code of the request
}

To send tweet, you need to type:

Send-Tweet -Message "Hello World!" -Username userxyz

Notice I did not include –Password. Infact, I did not include $Password in parenthesis after function. This way even if you were using tab to cycle through available parameters, you won’t see “Password” as a parameter. It still won’t stop you from typing:

Send-Tweet -Message "Hello World!" -Username userxyz -Password password

But by not declaring the parameter, I am encouraging one to skip typing password in plain-text. When user sends tweet using first option (without password) this script will prompt user for password. How is it secure? Notice –assecurestring when I am prompting user for password. This way your entry will show up as ****** instead of plaintext. If you were to use second method, you will type your password in plaintext and I am assuming you will do that when you are sure your screen is not visible to anyone else.

Another nice feature in my script is, I am using https in URL. This way I am sending authentication string over SSL. Shay’s original script for direct message does not use SSL hence username and password is transmitted in base64 encoding of string “username:password”. Your tweet will be published and will be in public domain but I don’t like the idea of transmitting username and password the same way. Here’s why:

The network capture shows the following:

image

Now let’s see what we can do with highlighted string in PowerShell:

PS> $b64upass = "dXNlcm5hbWU6cGFzc3dvcmQ="
PS> $bytes = [convert]::FromBase64String($b64upass)
PS> $decoded = [System.Text.Encoding]::UTF8.GetString($bytes)
PS> $decoded
username:password

So as you can see, even though Base64 is not plaintext, it’s very easy to decode and your username and password is more valuable than that!

If you are going to use Shay’s script for direct tweets, you can simply change URL to https and it should transmit securely. you can also use other ideas from my script to make password entry more secure.

Here’s another way of doing it:

$Tweetcred = Get-Credential
$UserName=$Tweetcred.GetNetworkCredential().UserName
$Password=$Tweetcred.GetNetworkCredential().Password

Using this method simply asks user for username and password in standard windows security dialog box and stores it in credential object of the OS.

image

I thank Shay for showing me way and hope you will benefit from both his and my scripts!

Update: Including link to Wikipedia article on HTTP Basic Access Authentication for reference.

  • Share/Bookmark
Print

Tags: , , ,

Exchange 2007 PowerShell Scripts – What would you like to script?

I am always thinking about how can I script/automate tasks I have to do repeatedly or I see others ask for. I would like to go a step beyond. I would like to ask you – the readers:

If you would want to script something for your Exchange 2007 environment, what would it be?

I am going to keep comments open on this one so please comment and provide me the list you would like to see scripts on. You can also use contact form if you like.

  • Share/Bookmark
Print

Tags:

Get-Service StartupType

If you want to find out startup type of a service using Get-Service cmdlet, you are out of luck. Get-Service cmdlet does not have StartupType property. Set-Service however does. So how can you find out the startup type of a service using powershell?

You can use Get-WmiObject.

(Get-WmiObject Win32_Service -filter "Name='W32Time'").StartMode

Once you determine the startup type of desired service, you can change it using Set-Service cmdlet:

Set-Service W32Time - StartupType Manual
  • Share/Bookmark
Print

Tags:

Measure script run time

When I am writing PowerShell scripts, one thing that is always in my mind: How long will it take to run this script and what can I do to reduce the run time.

While optimizing the code itself is not the scope of this article, what I am going to write may help you determine how long your script, function or code sections takes to run.

Insert the following at start of the section of code you want to check:

# Get Start Time
$startDTM = (Get-Date)

Insert the following at the end of the section of code you want to check:

# Get End Time
$endDTM = (Get-Date)
 
# Echo Time elapsed
"Elapsed Time: $(($endDTM-$startDTM).totalseconds) seconds"

Here is an example of my code optimization:

BEFORE (Run Time 40.4 seconds):

filter GetMailboxCount{
$Server = $_
 
$strFilter = "(&(&(& (mailnickname=*) (| (&(objectCategory=person)(objectClass=user)(msExchHomeServerName=$Server)) ))))"
 
$objDomain = New-Object System.DirectoryServices.DirectoryEntry
 
$objSearcher = New-Object System.DirectoryServices.DirectorySearcher
$objSearcher.SearchRoot = $objDomain
$objSearcher.PageSize = 1000
$objSearcher.Filter = $strFilter
$objSearcher.SearchScope = "Subtree"
 
$colResults = $objSearcher.FindAll()
$colCount = ($colResults | Measure-Object | %{$_.Count})
"$Server,$colCount"
 
}

AFTER (Run Time 4.53 seconds):

filter GetMailboxCount{
$Server = $_
 
$strFilter = "(&(&(& (mailnickname=*) (| (&(objectCategory=person)(objectClass=user)(msExchHomeServerName=$Server)) ))))"
 
$objDomain = New-Object System.DirectoryServices.DirectoryEntry
 
$objSearcher = New-Object System.DirectoryServices.DirectorySearcher
$objSearcher.SearchRoot = $objDomain
$objSearcher.PageSize = 1000
$objSearcher.Filter = $strFilter
$objSearcher.SearchScope = "Subtree"
 
$colProplist = "name"
$retval = $colProplist | foreach {$objSearcher.PropertiesToLoad.Add($_)}
 
$colResults = $objSearcher.FindAll()
$colCount = ($colResults | Measure-Object | %{$_.Count})
"$Server,$colCount"
 
}

As you will see the “name” property is irrelevant to my code but by querying on indexed attribute and limiting scope of the query, I was able to improve run time ten folds. Now that is huge time savings when you have to run this code in a loop across all of your servers!

  • Share/Bookmark
Print

Tags:

Corrupt or Missing Performance Counters

One of the functions in the code I posted in “Check Exchange 2003 vitals with PowerShell” is to check performance counters. When running the script, you may encounter an error:

Get-WmiObject : Invalid Class

 

This could happen for 2 reasons:

1: You have a typo in Perf Counter object.

2: The performance counter is missing on the host you are checking.

 

When this happened to me, I checked and verified this by loading performance monitor on affected server and trying to load Memory counters which the code was checking for. To no surprise, I found that the server did not have Memory object.

There are many reasons why the performance object could go missing from the OS. The KB article “How to manually rebuild Performance Counter Library values” explains how you can resolve this problem and bring the missing performance counter objects back.

  • Share/Bookmark
Print

Tags: , ,

Check Exchange 2003 vitals with PowerShell – Part II

In continuation to my previous post “Check Exchange 2003 vitals with PowerShell”, I also have a code block that you can replace if you want to query all exchange servers in your environment dynamically with script instead of using text file as in the code I posted earlier.

In the code I posted earlier, the following lines read the file servers.txt.

1
2
3
# Read file and store server names in variable
 
$Servers = (Get-Content .\servers.txt)

Replace it with the following, which queries Active Directory for objectclass msExchExchangeServer and returns all servers found.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
# Get Exchange Servers from Active Directory
 
function GetExchangeServers()
{
	# Set variables to connect to Active Directory, searching Configuration Naming Context
	$root= New-Object System.DirectoryServices.DirectoryEntry("LDAP://RootDSE")
	$configpartition = [adsi]("LDAP://CN=Microsoft Exchange,CN=Services," + $root.configurationNamingContext)
 
	# Set variables for search criteria
	$search = New-Object System.DirectoryServices.DirectorySearcher($configpartition)
	$search.filter = '(objectclass=msExchExchangeServer)'
 
	# Perform Serach, this will return all Exchange Server objects
	$ExchServer = $search.FindAll()
 
	# Output Name property of each server object stored in ExchServer array
	$ExchServer | foreach {$_.properties.name}
 
	# Comment the line above and uncomment the line below if you want to search specific Exchange servers by name
	# The example filter below will only output servers that have MBX in their name (i.e. MBX01, SRVMBX45 etc.)
	#$ExchServer | foreach {$_.properties.legacyexchangedn -match "MBX"}
}

You will also have to replace the lines:

1
2
# Get vitals for each server stored in $Servers array
$Servers | %{getVitals}

with the following:

1
2
# Get vitals for each server stored in $Servers array
GetExchangeServers | %{getVitals}


Comments welcome.

  • Share/Bookmark
Print

Tags: ,

Check Exchange 2003 vitals with PowerShell

I have written recently about Free System PTEs and /PAE usage in Exchange 2003 mailbox servers.

I set out to write a PowerShell script that will run against given list of servers and report back certain vitals including boot.ini settings, SystemPages registry setting and current performance data for Free Sytem PTEs and Pool Non-Paged Bytes.

 

The output csv can be used as a checkpoint for server health and can be used for reporting matrix. The script can easily be modified to add more performance counters and registry checks as necessary.

 

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
# Read file and store server names in variable
 
$Servers = (Get-Content .\servers.txt)
 
# Write header in output file
 
# Store header in variable
$headerLine =
@"
 
Server Name,Boot String,3GB,PAE,UserVA,Basevideo,SystemPages,Free System PTEs, Pool Non-Paged Bytes
"@
 
# Write header to file
$headerLine | Out-File .\results.csv -Encoding ASCII -Append
 
function getVitals()
 
{
	# Set server to connect to
	$Server = "$_"
 
# Read SystemPages from servers
 
	# Set Registry Key variables
	$REG_KEY = "System\\CurrentControlSet\\Control\\Session Manager\\Memory Management"
	$VALUE = "SystemPages"
 
	# Open remote registry
	$reg = [Microsoft.Win32.RegistryKey]::OpenRemoteBaseKey('LocalMachine', $Server)
 
	# Open the targeted remote registry key/subkey
	$regKey= $reg.OpenSubKey($REG_KEY)
 
	# Read and Store SystemPages value in variable
	$SystemPages = $regkey.getvalue($VALUE)
 
	# Close the Reg Key
	$regKey.Close()
 
# Read Boot.ini from Servers
 
	# Store Boot.ini contents in variable
	$iniContent = Get-Content "\\$Server\c$\boot.ini"
 
	# Store Boot string and values in variables
	$bootString = $iniContent[4] -replace ","," "
	$userva = ($bootString -split " " | foreach {if ($_ -match "userva") {$_}} | foreach {$_ -replace "/userva=",""})
 
	if ($iniContent[4] -match "3gb") {$3gb="Present"} else {$3gb="Missing"}
	if ($iniContent[4] -match "PAE") {$pae="Present"} else {$pae="Missing"}
	if ($iniContent[4] -match "basevideo") {$basevideo="Present"} else {$userva="Missing"}
 
# Read System Pages and NPP values from Performance Counters
 
	# Read performance counters
	$freeSPTEs = (Get-WmiObject Win32_PerfFormattedData_PerfOS_Memory -ComputerName $Server).FreeSystemPageTableEntries
	$poolNPBytes = (Get-WmiObject Win32_PerfFormattedData_PerfOS_Memory -ComputerName $Server).PoolNonPagedBytes
 
# Write data to file
 
	# Store result string in a variable
	$result = "$Server,$bootString,$3gb,$pae,$userva,$basevideo,$SystemPages,$freeSPTEs,$poolNPBytes"
 
	# Write results to file
	$result | Out-File .\results.csv -Encoding ASCII -Append
 
}
 
 
# Get vitals for each server stored in $Servers array
$Servers | %{getVitals}
  • Share/Bookmark
Print

Tags: ,

Force Mount-Database

I wanted to mount All mailbox databases from all servers that had them. This was a scenario where I had servers recovered with no DB files. I did not need them, I was going to start with empty databases. The command was going to be simple:

Get-MailboxDatabase | Mount-Database -Confirm:$false

Except that this command had a major flaw. Can you guess?

Read the rest of this entry »

  • Share/Bookmark
Print

Tags: , , , , ,