Saturday, August 18, 2007

Getting System up time (locally)


Here is another way to get your servers up time (total time since last reboot).
This method works locally.

The .NET Environment class exposes the TickCount property. TickCount Gets the number of milliseconds elapsed since the system started. It's a 32-bit signed integer type and by its restrictions it will be "reset" back to zero every 49.7 days (see Environment.TickCount Property on MSDN).

>> [environment]::tickcount;
297580406

To format the result to something more meaningful we'll use the New-TimeSpan cmdlet.
New-TimeSpan doesn't expose a milliseconds parameter so we'll divide the tickcount result by 1000 and feed the New-TimeSpan -seconds parameter.

>> New-TimeSpan -seconds ([environment]::tickcount / 1000);

Days : 3
Hours : 10
Minutes : 42
Seconds : 42
Milliseconds : 0
Ticks : 2977620000000
TotalDays : 3.44631944444444
TotalHours : 82.7116666666667
TotalMinutes : 4962.7
TotalSeconds : 297762
TotalMilliseconds : 297762000

So, to get only the days since last reboot:

>> (New-TimeSpan -seconds ([environment]::tickcount / 1000)).days;
3

Another formatting variation:

>> $sup = New-TimeSpan -seconds ([environment]::tickcount / 1000);
>> [string]::format("D:{0:00},H:{1:00},M:{2:00}",$sup.days,$sup.hours,$sup.minutes);

D:03,H:10,M:53

But wait, There's more. Browsing to the TimeSpan class page at MSDN reveals that TimeSpan class has a TimeSpan.FromMilliseconds Method.

>> [timespan] gm -static fr*;

TypeName: System.TimeSpan
Name MemberType Definition
---- ---------- ----------
FromDays Method static System.TimeSpan FromDays(Double value)
FromHours Method static System.TimeSpan FromHours(Double value)
FromMilliseconds Method static System.TimeSpan FromMilliseconds(Double value)
FromMinutes Method static System.TimeSpan FromMinutes(Double value)
FromSeconds Method static System.TimeSpan FromSeconds(Double value)
FromTicks Method static System.TimeSpan FromTicks(Int64 value)


Now, we can provide milliseconds to TimeSpan in a "static notation form":

>> $sup = [timespan]::FromMilliseconds([environment]::tickcount);
>> [string]::format("{0:00}:{1:00}:{2:00}",$sup.days,$sup.hours,$sup.minutes);

03:11:04

Note: If the returned values are negative, we can use the [math]::abs method to return absolute values.

Shay

Wednesday, August 8, 2007

Suspected in blog spamming


My Blogger account wont let me post. After logging in I found the following message:

 

#########################

WARNING
This blog has been locked by Blogger's spam-prevention robots. You will not be able to publish your posts, but you will be able to save them as drafts.

Blogger's spam-prevention robots have detected that your blog has characteristics of a spam blog. Since you're an actual person reading this, your blog is probably not a spam blog.
Automated spam detection is inherently fuzzy, and we sincerely apologize for this false positive.

We received your unlock request on August 7, 2007. On behalf of the robots, we apologize for locking your non-spam blog. Please be patient while we take a look at your blog and verify that it is not spam.

##########################

 

Say what??? On behalf of the robots??? The only thing in this blog is code oriented, nothing with spam keywords and the amount of posts is certainly not in a volume of a spam , strange.

Anyway, my unlock request was sent half day ago and still I *cant* publish anything? So how can you read this? Well, it turns out that publishing is still possible using Windows Live writer. Windows live writer, in some way, is bypassing the mechanism used by Blogger.

 

So if you are one of the Blogger team, CLOSE THIS HOLE and let me post!

Shay

Tuesday, August 7, 2007

IP decimal to binary conversion and back

 

Just playing around with IP numbers. here are two PowerShell one-liners for the job.

 

$ip = "192.168.0.1";

# convert to binary form
$sbin=[string]::join(".",($ip.split(".") | % {[System.Convert]::ToString($_,2).PadLeft(8,"0")}))   
$sbin


11000000.10101000.00000000.00000001

# convert the result back to decimal
[string]::join(".",($sbin.split(".") | % {[System.Convert]::ToByte($_,2)}))
192.168.0.1

This one-liners can be converted to functions in order to use them in the pipeline thus converting bulk ip numbers easily and PowerShelly ;)

Exchange 12 Rocks!



I have to prepare my environment for Exchange 2007. Cool, now I'll have the chance to use PowerShell in a more broad scope. In the research on how to coexist Exchange 2003 and Exchange 2007 I came up on this Easter egg thing.


When installing Exchange 2007, the setup creates the Exchange Routing Group and the Exchange Administrative Group with some characters strings that looks very odd.







I Googled for it and found two blog posts (see below) . Well, It turns out to be logical. It's a famous Caesar cipher with offset of 1. Both strings shows the same result. The Exchange Routing Group string should be shifted one char up while Exchange Administrative Group's offset is 1 down.



My fingers started to get itchy, so I fired PowerShell and started coding:

[char[]]'FYDIBOHF23SPDLT' | % {$s=''}{$s+=[string][char]([int][char]$_-1)}{$s}
[char[]]'DWBGZMFD01QNBJR' | % {$s=''}{$s+=[string][char]([int][char]$_+1)}{$s}



Run the commands and watch the output. Now, all I have to say is:
MPOH!MJWF!QPXFSTIFMM



Resources:
Jim McBee's Web Log
MSExchange.org

Shay

Monday, July 23, 2007

All-in-one feed reader

For a long time I used some kind of blog reader application for blogs and Outlook Express to read newsgroups. Switching between the applications was very annoying each time I wanted to send/receive items.

Then Outlook provided a way to check blogs, and I found another application that incorporated newsgroups into Outlook, that wasn't the perfect solution I needed.

Then I came up on a free RSS Reader and Newsgroup Aggregator called Omea. This application gives you all you need, RSS reader, NNTP news reader and a lot more. Its GUI is great and user friendly, once you use it you wont stop.

Check it out, it's totally FREE! thumbs UP for the JetBrain team, they could have easily charge for it.

Sunday, July 22, 2007

What's *dat* parameter?

 

When you want to find out how things are working in PowerShell, the first command to check is the get-help command. The help cmdlet can be used in various ways:

help <command>
man <command>
<command> -?
help about*

and there are a few more ways to achieve the same thing.

 

You can ask PowerShell to view different sections of the help by adding some switches like -detailed, -full or even
-examples to get the examples section of the command.

There is also the parameters section that lists all parameters a cmdlet supports. To list
all accepted parameters, type:

get-help <command> -parameter *

 

PowerShell also supports a shortened notation of parameters. If a cmdlet has a parameter
named -include, then you can type -i as long as there is no additional parameter
that starts with "i". In the case of multiple parameters that start with the
same characters, you need to distinguish the parameter by adding another character, something like:

Select-String -inc # -include 
Select-String -inp # -inputObject

 

Most of the time typing get-help to discover parameters results in a few help pages,
and navigating them to find what you need can be a very long process, not to mention how your console looks like
when you want to see the last commands you have typed.

Another issue is commands written with abbreviated parameters. something like:

Set-Content -l "argument" -pas "argument" -fi "argument" -l "argument" -fo

 

which you need to decipher by yourself. Although you can guess the parameter objective
by its argument, it can be quite a deciphering process.

This is where this utility function comes in hand. I wrote it as a learning tool for parameters.
It will print out three columns for the given cmdlet (you can add more):
1.      parameter name
2.      Alias, new column which calculates the distinguished part of the parameter.
3.      positioned column

 

 

So, to get all params for select-string cmdlet

PS C:\Scripts>get-params select-string

-----------------
- select-string -
-----------------

name                alias    position   Type
----                   -----     --------     ----
caseSensitive     -c        named    SwitchParameter
exclude              -e       named    string[]
include               -inc     named    string[]
inputObject        -inp     named    psobject
list                     -l        named    SwitchParameter
path                   -path   2           string[]
pattern              -patt    1            string[]
quiet                 -q        named    SwitchParameter
simpleMatch       -s        named    SwitchParameter
text                    -t        2            string[]

 

Looking good, now get only parameters starting with i*

PS C:\Scripts> get-params select-string i*

-----------------
- Select-String -
-----------------

name                alias    position   Type
----                   -----     --------     ----

include               -inc     named    string[]
inputObject        -inp     named    psobject

 

 

Generate a "cheat-sheet" for all cmdlets:

Get-Command | % {get-params $_.name} >  c:\AbbreviatedParameters.txt

 

Some command-lets do not support the parameters property (or globbing) and will render an error:

Get-Help : No parameter matches criteria *.
At line:1 char:9
+ get-help  <<<< Get-AuthenticodeSignature -param *

######## UNSUPPORTED CMDLETS ######
Get-AuthenticodeSignature
Get-Credential
Get-Culture
Get-ExecutionPolicy
Get-Host
Get-PfxCertificate
Get-PSProvider
Get-TraceSource
Get-UICulture
Import-Clixml
Import-Csv
Invoke-Expression
Out-Default
Out-Null
Stop-Transcript
Write-Debug
Write-Output
Write-Verbose
Write-Warning

 

One last thing, PowerShell maintains a short notation for its common parameters:

Verbose       {vb}
Debug         {db}
ErrorAction   {ea}
ErrorVariable {ev}
OutVariable   {ov}
OutBuffer     {ob}

 

 

Here is the code for get-params:

function get-params{
        param(
                [string]$cmd = $(throw "Please specify cmdlet name"),
                [string]$pat="*"
        )
        $ErrorActionPreference = "SilentlyContinue";
        # check the existence of the command-lets.
        $check = get-command | ? {$_.CommandType -eq "Cmdlet" -and $_.name -eq $cmd}
        if($check -eq $null){
                write-warning "No such command [$cmd]";
                return;
        }

        # some command-lets do not support the parametrs property.
        $check = @(get-help $cmd -parameter * -ea silentlyContinue).count
        if($check -eq $null -or $check -eq 0){
                write-warning "No parameters found for [$cmd]";
                return;
        }      

        $obj = get-help $cmd -parameter $pat;

        $obj | add-Member -memberType noteProperty -name alias -value "" -force;       
        $params = $obj | % {$_.name}

        for($i=0;$i -le $obj.length;$i++){

                [bool]$exitFlag = $false;

                for($x=0;$x -le $params[$i].length -and !($exitFlag);$x++){            
                        $regex = "^" + $params[$i].substring(0,$x);            
                        if(($params -match $regex).count -eq 1){
                                $exitFlag=$true;
                                $obj[$i].alias = ("-"+$regex.substring(1,$regex.length-1)).tolower();
                        }
                }
        }

        [int]$len="-[$cmd]-".length;
        write-host
        "-" * $len ; "- $cmd -" ; "-" * $len;
        $obj | select Name,Alias,Position,@{n="Type";e={$_.type.name}}| sort name | ft -auto

}

 

Enjoy!

Wednesday, July 18, 2007

Instant Regedit access

This is a variation of an older post Open In Regedit (IE Context Menu) . This helps when you navigate the registry provider and you want to open regedit in the current key your working on.

Regedit maintains the last opened key under HKCU\Software\Microsoft\Windows\CurrentVersion\Applets\Regedit\LastKey subkey, and it automatically updates this subkey each time you close regedit.

We can takes advantage of that by updating the value of the key from PowerShell and then run regedit. To run the function simply pass it the $pwd variable. To reuse it, included it in your profile.

##### jump to regedit.exe in a specified key path ######

function jump-regedit{
param( [string]$path = $(throw "Please provide Path.") )
# close regedit if open
stop-process -n regedit -ea silentlycontinue
$regKey="HKCU:\Software\Microsoft\Windows\CurrentVersion\Applets\Regedit";
# sp = Set-ItemProperty
# iex = Invoke-Expression sp $regKey -name "LastKey" -value "My Computer\$(convert-path $path)";
iex "regedit.exe";
}
set-alias jreg jump-regedit
 

function Jump-Regedit{
    Stop-Process -name regedit -errorAction silentlycontinue
    $regKey="HKCU:\Software\Microsoft\Windows\CurrentVersion\Applets\Regedit"
    Set-ItemProperty $regKey -name LastKey -value "My Computer\$(convert-path $pwd)"
    regedit.exe
}

set-alias jreg jump-regedit

 

#### USAGE ####

PS HKLM:\SOFTWARE\Microsoft> jreg
 

Shay