CMD and SG 2010 – Part 4.

Monday at my door and I’m really worried about it. Deadline is approaching and we have no chance to meet the goal. I hate it when somebody is leading a project in a way, that prevents members from doing things in a proposed schedule. Anyway, Thursday is pretty close so I’m slowly getting excited. And still 4 scripts to go in my cmd series. So here is the one that took me most of time to figure out, mainly because both in VBS and in Powershell it was usually done with COM object, and I have no idea how to use those in CMD. But then I thought, that this type of information has to be in the registry somewhere, looked for it a while, and – there it was. 🙂

CMD, using GeSHi – Beginner Event 7
  1. @echo off
  2. set /a Counter=0
  3. set AdminPath=Empty
  4. for /f "delims=" %%A in (‘reg query "hklmsoftwaremicrosoftwindowscurrentversionexplorershell folders" /v "Common Administrative Tools" ^| find "Administrative Tools"’) do call :ProcessResult %%A
  5. for %%F in (%AdminPath:~0,-2%*.lnk") do call :CountAndDisplay "%%~nF"
  6. echo Done! Total %Counter% items . . .
  7. goto :EOF
  9.   :ProcessResult
  10.   if [%AdminPath%]==[Empty] (
  11.     if [%1]==[REG_SZ] (
  12.     set AdminPath="
  13.     ) else (
  14.       shift
  15.       goto :ProcessResult
  16.     )
  17.   )
  18.   :JoinPath
  19.   if [%1]==[] goto :EOF
  20.   set AdminPath=%AdminPath%%1
  21.   goto :JoinPath
  23.   :CountAndDisplay
  24.   echo %~1
  25.   set /a Counter+=1
  26.   goto :EOF

I’m almost sure there is easier way to get only path from reg output. But this one works too, so I do not really care. 😉

Script # 8 was easier to write, but I still seem to have some problems with output. Anyway – it works better than I would expect, so I left it like that.

CMD, using GeSHi – Beginner Event 8
  1. @echo off
  2. echo Process Owner
  3. for /f "skip=1" %%I in (‘wmic PROCESS where "Name!=’wmic.exe’" get ProcessID’) do call :GetOwners %%I
  4. echo Done!
  5. goto :EOF
  7.     :GetOwners
  8.     SET ID=%1
  9.     for /f "delims=" %%P in (‘wmic PROCESS where "ProcessID=’%ID%‘ and name!=’wmic.exe’" get name ^| findstr /r /v "^$ ^Name"’) do (
  10.       set Process=%%P
  11.     )
  12.     for /f "tokens=2,3 delims=;= " %%O in (‘wmic PROCESS where "ProcessID=’%ID%‘ and name!=’wmic.exe’" call getowner ^| find "User"’) do (
  13.       set Owner=%%~O %%P
  14.     )
  15.     echo %Process% %Owner%
  16.     goto :EOF

As you can see most of stuff is done with usage of wmic.exe – pretty handy tool I must admit. Even if gwmi is easier to use and remember. 😉

WMI remoting.

Q: What IT Pro does if he has too much work and too little time to do something interesting?

A: He does something interesting that will save him some time doing his work. 😉

Two good examples of that today. First – we were asked by user to help him with installing citrix stuff for remote app. We could use OCS, VNC or other technique but hey, why not use PowerShell for that? I’ve read about Invoke-WMIMethod a while ago but never tried to use it. So I tried today, twice. First it was msi package to be installed: so we used Win32_Product:

PowerShell, using GeSHi

InvokeWmiMethod -ComputerName MyInvocation -Class Win32_Product -Name Install -ArgumentList @($true, $null, ‘c:tempPowerGUI.msi’)

Of course line used was different (PC, package) but worked as smooth as new PowerGUI. 😉

Next thing we tried was to install soft we needed on another remote machine. But because it reboots the machine once installed we have tested it on machine standing on our desk, just to see if it works. And because it’s .exe installation we used Win32_Process this time:

PowerShell, using GeSHi

InvokeWmiMethod -ComputerName MyInvocation -Class Win32_Process -Name Create -ArgumentList @(‘c:windowsnotepad2.exe’)

OK, but one thing I could not find: description of methods in PowerShell directly. Fortunately I had WMIExplorer that helped me get proper syntax, especially for Win32_Product – this method’s call is not intuitive at all…

Fathers day, fender bender and splatting $PsBoundParameters

Today was one of those days you would like to forget about as soon as possible. Morning it took me around 20 minutes to drive around 2 km. 3 maybe… Whole day was busy, and in the evening I received call from my boss who wanted to push me with some soft installation. It’s disk encryption solution and it’s mainly pain in the… back. And try to find arguments to convince a person that he or she should get new and cool smart card reader for the laptop that shipped with internal one just because software vendor is not able to provide proper support for some SC readers. You can see that smile on the face? That “thank you for wasting 0.5h of my time for something I will probably have only problems with” look? And once actual encryption will start – that “thank you for not being able to get my data back ‘cause I haven’t had time to do backup (THAT IS ALL YOUR FAULT!) and decrypting of drive lasts for ages” stare?

But that was only a beginning. Bright side was playing with PowerShell Plus console/ editor. It’s really cool! While playing with Quest cmdlet I decided that I need some function to narrow user searches to my location only. I decided to try splat something this time. And to be more geeky – to use $PsBoundParameters variable to do job for me. That’s what I come up with:

PowerShell, using GeSHi
  1. function GetWADuser {
  2. #requires -version 2.0
  3. param (
  4.         [switch]$Locked,
  5.         [switch]$Disabled,
  6.         [string]$FirstName,
  7.         [string]$LastName,
  8.         [string]$UserPrincipalName,
  9.         [string]$Email
  10. )
  11.         $WAR = ‘OU=WAR,DC=EU,DC=PXL,DC=INT’
  12.         GetQADUser @PsBoundParameters SearchRoot $WAR
  13. }

As you can see I’ve narrowed also parameters, but than – I haven’t used many others in global searches. And with that I can get rid of –SearchRoot when I want to return all user objects in my OU.

Soooo I finally left job, and was driving home listening to the PowerScripting podcast (recent episode). And than it was: a car I was sure already turned haven’t moved, and assuming it was not there anymore – I tried to turn too. Result as expected – not very bad, bad not good either. I wish I looked one last time before I started to speed up. 😦 It was of course all my fault, so I was happy that other driver was very kind and calm. I hope it was not serious. It did not look like something serious, but with that type of collision – you never know. I finally got home, expecting some surprise. And there it was: chocolate. With peanuts! 😦 Last year, even though I was at hospital with my daughter, I got brilliant card, with her hand and son’s feet. I still have it on my desk at work. I was hoping for replacement, but no – I will have to keep old ones. And I will have a desert tomorrow! Wonderful! (and yes, it was sarcasm). I don’t blame my wife, don’t get me wrong. I know that kids are hard to grasp and she does a great job with them. But still, I was little disappointed.

But I got my present: just before kids went to bed my daughter told me those magic words that people love to hear, and very often – love to say. Son would say the same I guess, but he’s not very fluent in Polish yet. 😉 Anyway: I knew than that whole this mess all they long was not so important. I’m father and today was my day. 😀 So today was hard day. But in the end – I’m glad. And happy. And those cards were so cool, that I’m happy I have good excuse to keep them for another year. 😉

CMD and SG 2010 – Part 3.

Monday. One day in week I’m not looking forward to and would sometimes like to erase it from calendar. Tomorrow will be hopefully different – mainly because we expect new furniture in our office. I really was looking forward to it, old ones didn’t behave well with stresses of equipment we kept inside (laptops, hard drives, switches…). New one should be fine with that. Will see…

One bad news: my meeting at podcast is postponed: it will happen on 1st July.

One good news: I have more time to prepare for it. But knowing myself long enough – it probably won’t have any effect on my preparations. I’m the ‘last minute’ type. Meaning: if I can do something later – I will do it too late. 😉

So now to the script. Event 5 – here I come equipped with CMD only! 😀 OK, I’ve used wmic.exe, but it’s not external tool for windows, so it’s valid. 🙂

CMD, using GeSHi – Beginner Event 5
  1. @echo off
  2. for /f "tokens=1,2" %%A in (‘wmic CPU GET Manufacturer^, MaxClockSpeed’) do CALL :Process %%A %%B
  3. echo CPU speed on %COMPUTERNAME% is %SPEED%. The maker is %Manu%.
  4. goto :EOF
  6.   :Process
  7.   if [%1]==[] goto :EOF
  8.   SET Manu=%1
  9.   SET SPEED=%2
  10.   goto :EOF

It’s using call :label technique I’ve learned ages ago. Almost like subs with pure ‘DOS’ as people tend to call it. Worked like charm so I have moved quickly to next event, which was quite big, and took me a while to get all pieces together. 😉

Script is pretty long:

CMD, using GeSHi – Beginner Event 6
  1. @echo off
  2. echo IP,ServiceState,ServiceStartMode,ComputerName,IsDomainMaster,MaintainServerList
  3. for /l %%N in (1,1,255) do CALL :CheckIP %%N
  4. goto :EOF
  6.     :CheckIP
  7.     SET IP=192.168.1.%1
  8.     ping %IP% -n 1 | find "bytes=" > nul || (
  9.         echo %IP% is not responding 1>&2
  10.         goto :EOF
  11.     )
  12.     for /f "tokens=1,2,3 skip=1 eol= " %%A in (‘wmic /node:%IP% SERVICE WHERE "Name=’Browser’" GET Started^, StartMode^, SystemName’) do call :SetService %%A %%B %%C
  13.     goto :EOF
  15.     :SetService
  16.     if [%1]==[] (
  17.         goto :EOF
  18.     )
  19.     if [%1]==[TRUE] (SET ServiceState=Running) ELSE (SET ServiceState=Stopped)
  20.     SET ServiceStartMode=%2
  21.     SET ComputerName=%3
  22.     for /f "tokens=3" %%I in (‘reg query \%ComputerName%HKLMSystemCurrentControlSetServicesBrowserParameters /v MaintainServerList ^| find "MaintainServerList"’) do SET MaintainServerList=%%I
  23.     for /f "tokens=3" %%I in (‘reg query \%ComputerName%HKLMSystemCurrentControlSetServicesBrowserParameters /v IsDomainMaster ^| find "IsDomainMaster"’) do SET IsDomainMaster=%%I
  24.     echo %IP%,%ServiceState%,%ServiceStartMode%,%ComputerName%,%IsDomainMaster%,%MaintainServerList%
  25.     goto :EOF

What I like about that script? It uses few of my favorite techniques:

  • || to react to an error (one can expect timeouts, so script should respond to it and send info about it to ‘error’ pipe
  • subs to make code more reliable and easier to read/ debug
  • separating stdout and errout with use of 1>&2
  • for here, for there – in cmd it’s ‘for’ everywhere. Here used, besides well known and often used ‘for /f’- way in for (i=0; i<max; i++) fashion.

If you redirect 2> nul – you won’t see any error. If you redirect 1> file.csv, you will see only errors and useful data will go to file. Should help to get decent file that excel can work with. No COM object required. 😉

Index your table. :)

Ever wanted to display format-table or select-object with index that you won’t have to calculate yourself? I did. Even though I don’t use ft very often. I played with it today a bit and came with rather simple solution:

PowerShell, using GeSHi
  1. $__counter = New-Object PSObject -Property @{Id=-1;Index=-1}
  2. $__indexFT = @{
  3.     Name=‘Index’
  4.     Expression={
  5.         if ($__counter.Id -ne $MyInvocation.HistoryId) {
  6.             $__counter.Index = 0
  7.             $__counter.Id = $MyInvocation.HistoryId
  8.         }
  9.         $__counter.Index
  10.         $__counter.Index++
  11.     }
  12.     Width = 6
  13.     Alignment = ‘Right’
  14. }
  15. $__indexSE = @{
  16.     Name=‘Index’
  17.     Expression={
  18.         if ($__counter.Id -ne $MyInvocation.HistoryId) {
  19.             $__counter.Index = 0
  20.             $__counter.Id = $MyInvocation.HistoryId
  21.         }
  22.         $__counter.Index;
  23.         $__counter.Index++
  24.     }
  25. }

Separate hast tables are there only because it’s illegal to use hash with not supported properties for that purpose, and because it looks nice in format-table if column has fine width and alignment. So all you had to do once you have it in module/ profile is:

gwmi win32_service | ft $__index, name, displayname => for good looking talbe or gwmi win32_service | select $__index, name. Should work fine in either way.

CMD and SG 2010 – Part 2.

Planned to do that almost a week ago, but man – it was a crazy week for me. A lot of work, a lot of travelling, a lot of unexpected issues and problems. Fortunately it’s getting peaceful now, so I have a chance to play a bit with Powershell and test tips and tricks I’ve learned during MS 50025 Training. 🙂 Meanwhile it’s time for next two scripts from cmd:

CMD, using GeSHi – Beginner Event 3
  1. @echo off
  2. if not exist C:FSO mkdir C:FSO
  3. pushd C:FSO
  4. >file10.txt echo CLASS:
  5. >>file10.txt echo DATE:
  6. >>file10.txt echo NOTES:
  8. for /l %%N in (1,1,9) do copy file10.txt file%%N.txt > nul

So simple, and yet do what it should. Next one:

CMD, using GeSHi – Beginner Event 4
  1. @echo off
  3.   echo Enough : %NUMBER_OF_PROCESSORS%
  4. ) ELSE (
  5.   echo Not enough : %NUMBER_OF_PROCESSORS%
  6. )

Even simpler. In fact it all started here – while playing with that event in VBS I was thinking: it would be even easier in cmd! And yes, it could be one line of code. I even mentioned it in my comment for SG entry. Judges gave me 2 stars but to be honest – I had no intention to get more. It would be embarrassing to add comments, help and error handling for something THAT simple. And I was shocked with suggestion from expert that if you want to check this in cmd – go grab my 10-line VBS to do so. No way! 😛 I will do it in one line of native cmd code! 😉

Meanwhile I learned new trick for powershell profile. I thought: how nice it would be to have PS window always as big as possible. So I played a bit with $host properties and I managed to get what I want. It was rather simple. See:

PowerShell, using GeSHi
  1. $MySize = $Host.UI.RawUI.MaxPhysicalWindowSize
  2. $MySize.Width –= 3 # We need scrollbar after all… 😉
  3. $MyBuffer = $MySize
  4. $MyBuffer.Height = 5000 # Set to any value you need – I like it looong. 😉
  5. $Host.UI.RawUI.BufferSize = $MyBuffer
  6. $Host.UI.RawUI.WindowSize = $MySize

And last but not least: I entered Powershell Portable beta program and – man – I’m loving it. :> Finally I will be able to carry PS with me to other workstation if I need it. After all not everything can be done via WMI, or even if it’s possible to do something remotely – you won’t have a chance to do that on a computer that has some network issues, right? 🙂

CMD and SG 2010 – Part 1.

First of all: I was third in SG this year. 🙂 It means I will have a chance to talk with Jeffrey Snover! Yupi!

That was a great news, but next one was even greater than first one: it will be on my favorite podcast, and Ed will be also there! How cool is that?! 🙂

I was thinking about 1000s of questions I could possibly ask, things I could say, and so long, and so forth. And while doing so I had to thing about how simple beginner events was. And I thought how cool it would be to get all events in cmd. And you know what? It worked! I learned few new tricks, so it was again learning experience. I would like to share my simple scripts, and because there is no cmd scripts repository (at least I failed to find one), I will have to copy it here. Good news – it was short, so it won’t be hard to read it. I don’t encourage you to use it however: go get Powershell and do it all in one line. 😉

CMD, using GeSHi – Beginner Event 1
  1. @echo off
  2. if [%1] == [] (
  3.   SET KEY="HKCUSoftwareScriptingGuys2010ScriptingGames"
  4. ) ELSE (
  5.   SET KEY=%1
  6. )
  8. if [%2] == [] (
  9.   SET VAL="LastUpdate"
  10. ) ELSE (
  11.   SET VAL=%2
  12. )
  14. if [%3] == [] (
  15.   SET DATA="%DATE%"
  16. ) ELSE (
  17.   SET DATA=%3
  18. )
  20. echo Setting key:%KEY% val:%VAL% with data:%DATA%
  21. REG ADD %KEY% /V %VAL% /D %DATA% /F

As you can see it work fine without any parameters, but it’s also possible to pass arguments to the script. No error handling, but I think it’s something I would not need anyway. 😉

So now for Beginner event no 2, where actual learning experience started. I’ve never used wmic.exe before. Fortunately I knew it existed and had something to start with. Read some help, googled a bit, and see what I got:

CMD, using GeSHi – Beginner Event 2
  1. @echo off
  2. set MyDate=Unknown
  3. for /f %%T in (‘wmic NTEVENT where "LogFile=’system’ and EventCode=’6005‘" GET TimeGenerated’) do call :SetDate %%T
  4. echo Last boot date: %MyDate%
  5. goto :EOF
  7.   :SetDate
  8.   if not [%MyDate%]==[Unknown] goto :EOF
  9.   if %1==TimeGenerated goto :EOF
  10.   SET TempDate=%1
  11.   SET Year=%TempDate:~0,4%
  12.   SET Month=%TempDate:~4,2%
  13.   SET Day=%TempDate:~6,2%
  14.   SET MyDate=%Year%%Month%%Day%
  15.   goto :EOF

Next two tomorrow. 🙂