Archive for the 'PowerShell' Category

RSS Feed for the 'PowerShell' Category

Looking at OpsMgr2007 Alert trend with Command Shell

Friday, January 25th, 2008

It's friday night, I am quite tired and I can't be asked of writing a long post. But I have not written much all week, not even updated my Twitter, and now I want to finish the week with at least some goodies. So this is the turn of a couple of Powershell commands/snippets/scripts that will count alerts and events generated each day: this information could help you understand the trends of events and alerts over time in a Management Group. It is nothing fancy at all, but they can still be useful to someone out there. In the past (MOM 2005) I used to gather this kind of information with SQL Queries against the operations database. But now, with Powershell, everything is exposed as objects and it is much easier to get information without really getting your hands dirty with the database :-)

#Number of Alerts per day

$alerttimes = Get-Alert | Select-Object TimeRaised
$array=@()

foreach ($datetime in $alerttimes){
$array += $datetime.timeraised.date
}

$array | Group-Object Date

#Number of Events per day

$eventtimes = Get-Event | Select-Object TimeGenerated
$array=@()

foreach ($datetime in $eventtimes){
$array += $datetime.timegenerated.date
}

$array | Group-Object Date

Beware that these "queries" might take a long time to execute (especially the events one) depending on the amount of data and your retention policy.

This is of course just scratching the surface of the amount of amazing things you can do with Powershell in Operations Manager 2007. For this kind of information you might want to keep an eye on the official "System Center Operations Manager Command Shell" blog: http://blogs.msdn.com/scshell/

Get-FlickrPhotos

Monday, January 14th, 2008

A while ago, talking to some friends, I was mentioning how cool it was that Flickr provides APIs, so that you can always get your data out of it, if you want to. There are several downloader applications that I found on the Internet, but I have not yet chosen one that I completey like among the few that I've tried. So, inspired by Kosso's PHP script for enumerating your photos on Flickr, I thought I'd port it to Powershell and make my own version of it. Just for the fun of it. My Powershell script does not do everything that Kosso's one does: I don't build a web page showing description and comments. I suppose this is because the original script was made with PHP, which you usually run on a web server and outputting as HTML is the standard thing you would do in PHP. I just concentrated on the "download" thing, since mine it is a console script. You can think of mine as a "full backup" script. Full… well, at least of all your photos, if not of all the metadata. It should be trivial to extend anyway, also considering Powershell XML type accelerator really makes it extremely easy to parse the output of a REST API such as Flickr's (I would say even easier and more readable that PHP'simplexml). There is a ton of things that could be extended/improved in the script… including supporting proxy servers, accepting more parameters for things that are now hardcoded… and with a million other things. Even this way, though, I think that the script can be useful to show a number of techniques in Powershell. Or just to download your photos :-) So you can download the script from here: Get-FlickrPhotos.ps1

Welcome www.powershell.it!

Friday, January 4th, 2008

I just read from Jeffrey Snover about this newly born Italian PowerShell community site.

I just created an account for myself on the site… as you know I like PowerShell, so even if I usually prefer writing stuff in english, I will try to hang out there and see how can I contribute to it.

After all, I am italian… :-)

Simply Works

Thursday, December 27th, 2007

Simply Works

Simply Works, uploaded by Daniele Muscetta on Flickr.

I don't know about other people, but I do get a lot to think when the end of the year approaches: all that I've done, what I have not yet done, what I would like to do, and so on…

And it is a period when memories surface.

I found the two old CD-ROMs you can see in the picture. And those are memories.
missioncritical software was the company that invented a lot of stuff that became Microsoft's products: for example ADMT and Operations Manager.

The black CD contains SeNTry, the "enterprise event manager", what later became Operations Manager.
On the back of the CD, the company motto at the time: "software that works simply and simply works".
So true. I might digress on this concept, but I won't do that right now.

I have already explained in my other blog what I do for work. Well, that was a couple of years ago anyway. Several things have changed, and we are moving towards offering services that are more measurable and professional. So, since it happens that in a certain job you need to be an "expert" and "specialize" in order to be "seen" or "noticed".
You know I don't really believe in specialization. I have written it all over the place. But you need to make other people happy as well and let them believe what they want, so when you "specialize" they are happier. No, really, it might make a difference in your carrer :-)

In this regard, I did also mention my "meeting again" with Operations Manager.
That's where Operations manager helped me: it let me "specialize" in systems and applications management… a field where you need to know a bit of everything anyway: infrastructure, security, logging, scripting, databases, and so on… :-)
This way, everyone wins.

Don't misunderstand me, this does not mean I want to know everything. One cannot possibly know everything, and the more I learn the more I believe I know nothing at all, to be honest. I don't know everything, so please don't ask me everything – I work with mainframes :-)
While that can be a great excuse to avoid neighbours and relatives annoyances with their PCs though, on the serious side I still believe that any intelligent individual cannot be locked into doing a narrow thing and know only that one bit just because it is common thought that you have to act that way.

If I would stop where I have to stop I would be the standard "IT Pro". I would be fine, sure, but I would get bored soon. I would not learn anything. But I don't feel I am the standard "IT Pro". In fact, funnily enough, on some other blogs out there I have been referenced as a "Dev" (find it on your own, look at their blogrolls :-) ). But I am not a Dev either then… I don't write code for work. I would love to, but I rarely actually do, other than some scripts. Anyway, I tend to escape the definition of the usual "expert" on something… mostly because I want to escape it. I don't see myself represented by those generalization.

As Phil puts it, when asked "Are software developers – engineers or artists?":

"[...] Don’t take this as a copout, but a little of both. I see it more as craftsmanship. Engineering relies on a lot of science. Much of it is demonstrably empirical and constrained by the laws of physics. Software is less constrained by physics as it is by the limits of the mind. [...]"

Craftmanship. Not science.
And stop calling me an "engineer". I am not an engineer. I was even crap in math, in school!

Anyway, what does this all mean? In practical terms, it means that in the end, wether I want it or not, I do get considered an "expert" on MOM and OpsMgr… and that I will mostly work on those products for the next year too. But that is not bad, because, as I said, working on that product means working on many more things too. Also, I can point to different audiences: those believing in "experts" and those going beyond schemes. It also means that I will have to continue teaching a couple of scripting classes (both VBScript and PowerShell) that nobody else seems to be willing to do (because they are all *expert* in something narrow), and that I will still be hacking together my other stuff (my facebook apps, my wordpress theme and plugins, my server, etc) and even continue to have strong opinions in those other fields that I find interesting and where I am not considered an *expert* ;-)

Well, I suppose I've been ranting enough for today…and for this year :-)
I really want to wish everybody again a great beginning of 2008!!! What are you going to be busy with, in 2008 ?

ITPro vs. Dev: there is no such a thing.

Tuesday, September 11th, 2007

Dave Winer wisely writes:

[...] I've been pushing the idea that every app should be a platform for a long time, that in addition to a user interface, every app should have a programmatic interface. For me the idea came from growing up using Unix in the 70s, where every app is a toolkit and the operating system is a scripting language. Wiring things together is an integral part of being a Unix user. It's why programmers like Unix so much [...]

It is entirely true. The limits are blurry, IMHO. In the Unix world it is common to find full-fledged "applications" which have been written by the ground up by people that were doing SysAdmin tasks, and those "applications" are usually just… scripts. Simple shell scripts, or something more evolved (PERL, PHP, Python) it does not really matter.

I am so tired of the division traditionally made in the Microsoft world between "Developers" and "IT Professionals". We even have separate sites for the two audiences: MSDN and Technet. There are separate "TechED" events: for"Devs" and for "IT Pros". There are blogs that are divided among the two "audiences"…

There aren't two different audiences, really. There are people, with various degrees of expertise. There is no such a thing as a "developer" if he doesn't know a bit how the underlying system works. His code is gonna suck. And there is not such a thing such a "IT Pro" that builds and integrates and manages systems if he does not have the palest idea of how things work "behind the GUI". He's gonna screw things up regardless of how many step-by-step (click-by-click ?) procedures you spoon feed him.

That's why automation and integration are best done by people who know how to write a bit code.

The PowerShell folk GET IT.

Powershell and RegExp: a "match" made my day.

Thursday, August 9th, 2007

Today I was working with a customer and friend (Claudio Latini, who I thank for the permission to post this, which is also work of his brain – especially the regular expression you'll see reading on!).

We are running several projects and activities together and, among several other things, he's in the process of migrating his users from Exchange 2003 to Exchange 2007. In this infrastructure, he has some ISA Server that publish both the Exchange2003 and the Exchange2007 frontends.

Now he wanted to know HOW MANY and WHICH ONES of his users actually have a PocketPC or other WIndows Mobile device and were actively connecting to the old FrontEnd. You give out mobile devices to people but those things are usually less "managed" – when compared to corporate PCs, at least. So you loose a bit control of the thing… usually people with mobile devices using ActiveSync in companies are managers, and especially since some of them might be on holiday at the moment, it was important to know WHO were the people that had to be told to reconfigure their device to point to the new name/server BEFORE he would start complaining about ActiveSync not working anymore…

So how do you figure out who's connecting ?

I am NO Exchange expert whatsoever… but a thing that came in handy was the thing that an ISA Server was reverse-publishing the frontend server. I know ISA (and firewalls/proxies in general) much better than Exchange, so I can help on that side. In the log files, ActiveSync Connections looked like the following URL, passing most parameters in the POST request: http://www.company.com/exchange?User=Mario&DeviceID=186hkjw6gjw76463uh2g5gi2j3h&Bla=bla (and on an unrelated note: yes, if you try to crawl this link, you are a bot :-) )

So we exported ISA logs (there are several tools for this, including "Extract logs", but we did not use a script, we just used a filter for the correct publishing rule in the "Monitoring – Logging" tag in ISA Server Console and then copied and pasted those log lines) and tried to see if PowerShell could help tackle the issue.

Here we load our sample log (in a real log you would have much more information – each single line wrapping several console rows; I cut it short to the URL to make it more readable.

PS> get-content log.txt    

http://www.company.com/exchange?User=Mario&DevideID=186hkjw6gjw76463uh2g5gi2j3h&Bla=bla

http://www.company.com/exchange?User=Gino&DevideID=186hkjw6gjw76463uh2g5gi2j3h&Bla=bla

http://www.company.com/exchange?User=Antonio&DevideID=186hkjw6gjw76463uh2g5gi2j3h&Bla=bla

http://www.company.com/exchange?User=Antonio&DevideID=186hkjw6gjw76463uh2g5gi2j3h&Bla=bla

http://www.company.com/exchange?User=Gino&DevideID=186hkjw6gjw76463uh2g5gi2j3h&Bla=bla

http://www.company.com/exchange?User=Antonio&DevideID=186hkjw6gjw76463uh2g5gi2j3h&Bla=bla

http://www.company.com/exchange?User=Antonio&DevideID=186hkjw6gjw76463uh2g5gi2j3h&Bla=bla

http://www.company.com/exchange?User=Mario&DevideID=186hkjw6gjw76463uh2g5gi2j3h&Bla=bla

http://www.company.com/exchange?User=Mario&DevideID=186hkjw6gjw76463uh2g5gi2j3h&Bla=bla

http://www.company.com/exchange?User=Mario&DevideID=186hkjw6gjw76463uh2g5gi2j3h&Bla=bla

http://www.company.com/exchange?User=Mario&DevideID=186hkjw6gjw76463uh2g5gi2j3h&Bla=bla

http://www.company.com/exchange?User=Antonio&DevideID=186hkjw6gjw76463uh2g5gi2j3h&Bla=bla

http://www.company.com/exchange?User=Antonio&DevideID=186hkjw6gjw76463uh2g5gi2j3h&Bla=bla

http://www.company.com/exchange?User=Mario&DevideID=186hkjw6gjw76463uh2g5gi2j3h&Bla=bla

http://www.company.com/exchange?User=Antonio&DevideID=186hkjw6gjw76463uh2g5gi2j3h&Bla=bla

http://www.company.com/exchange?User=Antonio&DevideID=186hkjw6gjw76463uh2g5gi2j3h&Bla=bla

http://www.company.com/exchange?User=Mario&DevideID=186hkjw6gjw76463uh2g5gi2j3h&Bla=bla

http://www.company.com/exchange?User=Antonio&DevideID=186hkjw6gjw76463uh2g5gi2j3h&Bla=bla

http://www.company.com/exchange?User=Antonio&DevideID=186hkjw6gjw76463uh2g5gi2j3h&Bla=bla

http://www.company.com/exchange?User=Mario&DevideID=186hkjw6gjw76463uh2g5gi2j3h&Bla=bla

http://www.company.com/exchange?User=Antonio&DevideID=186hkjw6gjw76463uh2g5gi2j3h&Bla=bla

http://www.company.com/exchange?User=Antonio&DevideID=186hkjw6gjw76463uh2g5gi2j3h&Bla=bla

http://www.company.com/exchange?User=Mario&DevideID=186hkjw6gjw76463uh2g5gi2j3h&Bla=bla

We know Get-Content does not just display the file, it loads the file into a string array.

So we can cycle through the file and try to extract (using a regexp) the string after "User=" and before the first ampersand ("&"), which translates in the following regular expression:

"User=(?<nome>.*?)&"

(the regexp has been the most difficult thing to figure out, but it is very worth the hassle once you've done it…)

PS> get-content log.txt | foreach {$_ -match "User=(?<nome>.*?)&" | out-null; $matches}
Name                           Value
----                           -----
nome                           Mario
0                              User=Mario& nome                           Gino
0                              User=Gino&
nome                           Antonio
0                              User=Antonio&
nome                           Antonio
0                              User=Antonio&
nome                           Gino
0                              User=Gino&
nome                           Antonio
0                              User=Antonio&
nome                           Antonio
0                              User=Antonio&
nome                           Mario
0                              User=Mario&
nome                           Mario
0                              User=Mario&
nome                           Mario
0                              User=Mario&
nome                           Mario
0                              User=Mario&
nome                           Antonio
0                              User=Antonio&
nome                           Antonio
0                              User=Antonio&
nome                           Mario
0                              User=Mario&
nome                           Antonio
0                              User=Antonio&
nome                           Antonio
0                              User=Antonio&
nome                           Mario
0                              User=Mario&
nome                           Antonio
0                              User=Antonio&
nome                           Antonio
0                              User=Antonio&
nome                           Mario
0                              User=Mario&
nome                           Antonio
0                              User=Antonio&
nome                           Antonio
0                              User=Antonio&
nome                           Mario
0                              User=Mario&
nome                           Mario
0                              User=Mario&

This seems to work. Now we only have to get the Named Captures called "nome" (containing the user name):

PS> get-content log.txt | foreach {$_ -match "User=(?<name>.*?)&" | out-null; $matches["name"]}
Mario
Gino
Antonio Antonio
Gino
Antonio
Antonio
Mario
Mario
Mario
Mario
Antonio
Antonio
Mario
Antonio
Antonio
Mario
Antonio
Antonio
Mario
Antonio
Antonio
Mario
Mario

Awesome. Now sort them and remove duplicates. Which is one more command in our pipeline:

get-content log.txt | foreach {$_ -match "User=(?<nome>.*?)&" | out-null; $matches["nome"]} | sort-object -uniq

P> get-content log.txt | foreach {$_ -match "User=(?<name>.*?)&" | out-null; $matches["name"]} | sort-object -uniq
Antonio
Gino
Mario     

PS>
PS>

Now you can call those three users and tell them to modify their ActiveSync configuration :-)

Death by right-click -> Delete ? Nope. PowerShell.

Wednesday, May 30th, 2007

So at one stage I was testing the RSS reader capabilities of Outlook 2007, and I imported an OPML file with roughly 500 feeds! Of course I was NOT interested in reading ALL of them, and it was causing quite a bit of work to do on my machine to fetch them all and sync the content in my mailbox…

So I figured out it was possible to remove the subscription (from the Tools menu -> Account Settings -> RSS Feeds) but the folders were left there. Now, I didn't want to have those 500 folders in my mailbox, and I did not even want to die by right-clicking, pressing "delete", confirming…. all of this 500 times! No way.

So I wrote this little PowerShell script, I guess it *might* be helpful to someone at one stage, who knows ?

[System.Reflection.Assembly]::LoadWithPartialName('Microsoft.Office.Interop.Outlook')
$oApp = New-Object -COM 'Outlook.Application'
$rss = $oApp.GetNamespace("MAPI").GetDefaultFolder("olFolderRssFeeds")
forach ($folder in $rss.Folders)
{
$folder.Delete()
}

Please note that if you don't have the Office Interop Assemblies installed on your machine, you can't use the first line. As a result, you will have to change the third line hardcoding the number that represents the RSSFeeds folder, so it would become:

$rss = $oApp.GetNamespace("MAPI").GetDefaultFolder(25)

Note: I found out (later, of course) that there is a much more general post on this subject (that is, automating Outlook through PowerShell): http://www.leeholmes.com/blog/GettingThingsDoneOutlookTaskAutomationWithPowerShell.aspx

Out-Flickr!!

Wednesday, January 10th, 2007

This is soooo cool! An "Out-Flickr" script for PowerShell:

http://abhishek225.spaces.live.com/blog/cns!13469C7B7CE6E911!285.entry

Out-Blog!

Friday, November 24th, 2006

[Edited again 25th November - Jachym gave me some suggestions and insights on the use of parameters, and I slightly changed/fixed the original code I had posted yesterday. There are still some more things that could be improved, of course, but I'll leave them to the future, next time I'll have time fot it (who knows when that will be?)]

This one is a post regarding my first test writing a cmdlet for PowerShell. After a few days since having change my blog's title to "$daniele.rant | Out-Blog" (where Out-Blog was a fantasy cmdlet name, and the title just meant to mimick PowerShell syntax in a funny way), I stumbled across this wonderful blog post: http://blog.boschin.it/archive/2006/09/21/4375.aspx that describes how to use the assemblies of "Windows Live Writer". Then I saw the light: I could actually implement an "Out-Blog" cmdlet. I am not sure what this could be useful for… but I thought it was funny to experiment with. I followed the HOW TO information on this other blog post to guide me through the coding: http://www.proudlyserving.com/archives/2005/10/lets_all_write_1.html

The result is the code that follows. you see is pretty much Boschin's code wrapped into a cmdlet class. Nothing fancy. Just a test. I thought someone might find it interesting. It is provided "AS IS", mainly for educational purpose (MINE, only mine…. I'm the one whose education is being improved, not you :-) )

 

 

using System;

using System.Collections.Generic;

using System.Text;

using System.Management.Automation;

using WindowsLive.Writer.BlogClient.Clients;

using WindowsLive.Writer.BlogClient;

using WindowsLive.Writer.CoreServices;

using WindowsLive.Writer.CoreServices.Settings;

using WindowsLive.Writer.Extensibility.BlogClient;

using Microsoft.Win32;

 

 

namespace LiveWriterCmdlet

{

[Cmdlet("out", "blog", SupportsShouldProcess=true)]

 

public sealed class OutBlogCmdlet : Cmdlet

{

[Parameter(Position = 0, Mandatory = true, ValueFromPipeline = false, ValueFromPipelineByPropertyName = true)]

[ValidateNotNullOrEmpty]

public string Title

{

get { return _title; }

set { _title = value; }

}

private string _title;

 

[Parameter(Position=1,Mandatory=true,ValueFromPipeline=true,ValueFromPipelineByPropertyName=true)]

[ValidateNotNullOrEmpty]

public string Text

{

get { return _text; }

set { _text = value; }

}

private string _text;

 

[Parameter(Position = 2, Mandatory = true, ValueFromPipeline = false, ValueFromPipelineByPropertyName = true)]

[ValidateNotNullOrEmpty]

public string BlogApiEndPoint

{

get { return _blogapiendpoint; }

set { _blogapiendpoint = value; }

}

private string _blogapiendpoint;

 

[Parameter(Position = 3, Mandatory = true, ValueFromPipeline = false, ValueFromPipelineByPropertyName = true)]

[ValidateNotNullOrEmpty]

public string UserName

{

get { return _username; }

set { _username = value; }

}

private string _username;

 

[Parameter(Position = 4, Mandatory = true, ValueFromPipeline = false, ValueFromPipelineByPropertyName = true)]

[ValidateNotNullOrEmpty]

public string Password

{

get { return _password; }

set { _password = value; }

}

private string _password;

 

 

[Parameter(Position = 6, Mandatory = false, ValueFromPipeline = false, ValueFromPipelineByPropertyName = true)]

[ValidateNotNullOrEmpty]

public string ProxyAddress

{

get { return _proxyaddress; }

set { _proxyaddress = value; }

}

private string _proxyaddress;

 

[Parameter(Position = 7, Mandatory = false, ValueFromPipeline = false, ValueFromPipelineByPropertyName = true)]

[ValidateNotNullOrEmpty]

public int ProxyPort

{

get { return _proxyport; }

set { _proxyport = value; }

}

private int _proxyport;

 

[Parameter(Position = 8, Mandatory = false, ValueFromPipeline = false, ValueFromPipelineByPropertyName = true)]

public string ProxyUserName

{

get { return _proxyusername; }

set { _proxyusername = value; }

}

private string _proxyusername;

 

[Parameter(Position = 9, Mandatory = false, ValueFromPipeline = false, ValueFromPipelineByPropertyName = true)]

public string ProxyPassword

{

get { return _proxypassword; }

set { _proxypassword = value; }

}

private string _proxypassword;

 

[Parameter(Position = 10, Mandatory = false, ValueFromPipeline = false, ValueFromPipelineByPropertyName = true)]

public SwitchParameter Published

{

get { return _published; }

set { _published = value; }

}

private bool _published;

 

 

 

 

protected override void BeginProcessing()

{

base.BeginProcessing();

 

 

ApplicationEnvironment.Initialize();

if ((ProxyAddress != null) | (ProxyAddress != ""))

{

WebProxySettings.ProxyEnabled = true;

WebProxySettings.Hostname = ProxyAddress;

WebProxySettings.Port = ProxyPort;

WebProxySettings.Username = ProxyUserName;

WebProxySettings.Password = ProxyPassword;

 

}

else

{

WebProxySettings.ProxyEnabled = false;

}

 

}

 

 

 

 

protected override void ProcessRecord()

{

if (ShouldProcess(Text))

{

ISettingsPersister persister = new RegistrySettingsPersister(Registry.CurrentUser, @"Software\Windows Live Writer");

IBlogCredentials credentials = new BlogCredentials(new SettingsPersisterHelper(persister));

IBlogCredentialsAccessor credentialsAccessor = new BlogCredentialsAccessor("dummy-value", credentials);

 

credentials.Username = UserName;

credentials.Password = Password;

 

MovableTypeClient client = new MovableTypeClient(new Uri(BlogApiEndPoint), credentialsAccessor, PostFormatOptions.Unknown);

 

 

BlogPost MyPost = new BlogPost();

MyPost.Title = Title;

MyPost.Contents = Text;

client.NewPost("dummy-value", MyPost, Published);

 

WriteVerbose("Posted Successfully.");

 

}

 

}

 

}

}