Friday, September 26, 2008

Moving my power to other blog

Hi there, fortunately I found out that in the Czech Republic (where I live) is free the domain powershell.cz. Therefore I registered it and moved my power to localization of PS scripts to Czech language. I'll be publishing more posts here but now I'll maily focus to PowerShell.cz.

Saturday, September 6, 2008

Available drive letters

My colleague needed to run subst command and therefore was looking for available drive letters. During the script creating I found out that running simple InStr() function is slower then to use Dictionary object (maybe it's a tip for other blogpost). Anyway I used InStr() because I stopped the script after first match.

Const wbemFlagReturnImmediately = &h10
Const wbemFlagForwardOnly = &h20
Set WshNetwork = WScript.CreateObject("WScript.Network")
Computer = WshNetwork.ComputerName
Set objWMIService = GetObject("winmgmts:\\" & Computer & "\root\CIMV2")
Set colItems = objWMIService.ExecQuery("SELECT * FROM Win32_LogicalDisk", "WQL", wbemFlagReturnImmediately + wbemFlagForwardOnly)

For Each objItem In colItems
Disks = Disks & lcase(left(objItem.DeviceID,1))
Next

For I = 122 To 97 Step -1
Character = Chr(i)
If InStr (Disks, Character) Then
Else
Result = Character
Exit For
End If
Next

WScript.Echo "Available drive letter: " & Result

The script connects to WMI and query all available logical disks. Then is stores the drive letter in string named Disks. As the drive letter is stored in DeviceID in form C: I converted it to lowercase and remove the colon. After the whole WMI part the Disks looks like this: "cdehpvx".

Then in For loop I am going thru alphabet from the end to the beginning (to say it exactly - from 'z' to 'i') and after first non-match exit the loop and return the letter.

Sunday, August 31, 2008

Retrieve list of installed programs

"Hi Dave, I'd like to list all installed software to text file for later parsing. My final point is to check if any of VMware software is installed."

OK, no problem for me. You have a lot of ways how to do that. Let me show you some of them.

1) From WMI via VBS
In this case we use Win32_Product WMI class and search it for specific software name:

Set objWMIService = GetObject("winmgmts:\\VMMORAVEC\root\CIMV2")
Set colItems = objWMIService.ExecQuery("SELECT * FROM Win32_Product WHERE name LIKE '%vmware%'", "WQL")

For Each objItem In colItems
WScript.Echo objItem.Name
Next

2) From WMI via wmic
This way is easy but takes long time. especially when we ran at as "runas" command it takes five minutes per computer which was not accepted by requestor. Anyway this is very useful method how retrieve data from WMI.

wmic product find /I "VMware"

3) From Registry via VBS
In this case we'll check registry but through WMI StdRegProv class.

Const HKLM = &H80000002
Const strBaseKey = "Software\Microsoft\Windows\CurrentVersion\Uninstall\"
Set objReg = GetObject("winmgmts://vmmoravec/root/default:StdRegProv")
objReg.EnumKey HKLM,strBaseKey,arrSubKeys

For Each strSubKey In arrSubKeys
intRet = objReg.GetStringValue(HKLM, strBaseKey & strSubKey, "DisplayName", strValue)
if InStr(strValue, "VMware") > 0 Then
WScript.Echo strvalue
End If
Next


4) From Registry via reg.exe
The way we used for our case. Fast and easy (and showing only VMware software):

reg query HKLM\Software\Microsoft\Windows\CurrentVersion\Uninstall /s ¦ find /I "VMware" ¦ find /I "DisplayName"

Output:

DisplayName REG_SZ VMware Infrastructure Client 2.5
DisplayName REG_SZ VMware Workstation
DisplayName REG_SZ VMware VI Toolkit (for Windows)

5) Do you want PowerShell version?
In PowerShell just use Get-WmiObject and pipe it like this:

Get-WmiObject Win32_Product ¦ Where {$_.name -match "vmware"} ¦ fl name

Conclusion
It's up to you which method you'd like to use. WMI is very powerful but slow and registry is sometimes hard to parse. As I mentioned before: for this case we used reg.exe because it fits perfectly our needs. Of course for other type of work you will choose different method.

Useful links

Saturday, August 30, 2008

Retrieve data from Lotus Notes with PowerShell

Last week when I was playing with PowerShell I tried to connect to my Lotus Notes (LN) mailbox and retrieve some data to console. After some minutes I'v just had an idea to try something more useful then read emails in text form. Let me describe the scenario.

In IT we use database where we store all data about our hardware. About it's assignments, lease time, specification, etc. I'd like to check all notebooks which are after their date of warranty.

First of all it's necessary to check names of LN field we will use. In this case it's Category, Type, Owner, End of warranty. If LN designer are good then it's easy to find it - in my case, I was lucky because names of fields were self-descriptive. I used accessing through COM and very helpful was Lotus Domino Designer Help.

Connect to the database and open the View

# Create LN Object
$DomSession = New-Object -ComObject Lotus.NotesSession

# Initialize LN Object
# You'll be asking for LN password to your id
$DomSession.Initialize()


# Connect to Server, select db and display the name
$DomDatabase = $DomSession.GetDatabase("LN007","IT\HW.nsf")
Write-Host "Database open : " $DomDatabase.Title

# Open specific View (By Serial Number)
$DomView = $DomDatabase.GetView('Serial Number')
Write-Host "View read : " $DomView.Name


# Show number of documents
$DomNumOfDocs = $DomView.AllEntries.Count
Write-Host "Num of Docs : " $DomNumOfDocs


# Get First Document in the View
$DomDoc = $DomView.GetFirstDocument()


So, we connected to the mentioned database (hw.nsf) which is located on the LN007 server. Then we found the right view, counted all documents in it and assigned first document into variable $DomDoc. Now let's have a look how to see the data.

Read fields for current document
Let's first see the script and then comment it

$i = 0
while ($DomDoc -ne $null) {
$item = [string] $DomDoc.GetItemValue("fldPurchaseDateEnd")

if ( $item.Trim().Length -ne 0 ) {
$tMonth,$tDay,$tYear = $item.split("/")
$tDate = "$tYear$tMonth$tDay"

if ( ( $currDate -gt $tdate ) -and ( $DomDoc.GetItemValue("fldHWCategory") -eq "Notebook" ) ) {
Write-host $DomDoc.GetItemValue("fldHardwareType")":" $DomDoc.GetItemValue("fldCurrentUser") ":" $item.substring(0,10)
$i++
} #if - date, HWcategory
} #if - length 0


$DomDoc = $DomView.GetNextDocument($DomDoc)
} #while

Write-Host "Out of leasing : " $i


I used while loop to go thru all documents in the view. GetItemValue is used for getting value of specific field. The rest is easy - if the length of fldPurchaseDateEnd is not zero (e.g. date exists) check the date and compare it with current (variable $currDate created at the beginning of the script this way:

$Date = [string] (Get-Date)
$Day,$Month,$Year,$Hour,$Minute,$Second = $Date.split(" .:/")
$currDate = "$Year$Month$Day"


this was necessary because of different interpretation of date in LN and Windows). If the date is older then today and HW Category is notebook then the type and current user are displayed. At the end of script is shown how many notebooks are out of warranty.

Useful links

Sunday, August 17, 2008

How to create file of specific size

"Hi Dave, I need to create file of specific size to test our SMS DP. Do you know easier way then to create text file and copy the text inside?"

Sure I know :) The question was really surprising to me. I see that there is still a lot of Windows admins who don't know basic commands. In this case, my recommendation is to use fsutil command which will create empty file of specific size.

fsutil file createnew c:\empty.txt 1024

will create file empty.txt and it's size is 1KB.

Friday, March 21, 2008

Computers without specific file

Normally you need to check computers where specific file is present. What to do if you need to find out computers without specific file. Simple query with just NOT IN command will not work. You need to create the query in this way:

SELECT DISTINCT
sys.Netbios_Name0

FROM v_R_System sys
INNER JOIN v_GS_SoftwareFile sf
ON sys.ResourceID = sf.ResourceID

WHERE sys.ResourceID NOT IN
(
SELECT DISTINCT sys.ResourceID
FROM v_R_System sys
INNER JOIN v_GS_SoftwareFile sf
ON sys.ResourceID = sf.ResourceID

WHERE sf.FileName = 'AcroRd32.exe'
)

ORDER BY 1

The key for the success is NOT IN command. It will select (from all computers) the ones which are not in select of computers containing requested software.

Thursday, January 24, 2008

Vítejte v mém počítačovém blogu

Jelikož mi v Microsoft Spaces Live nejsou schopni pomoci s mými problémy, rozhodl jsem se přejít na jinou službu. Chtěl bych zde publikovat své postřehy ohledně mých pracovních nástrojů, tj. převážně Windows Serveru, SMS Serveru a skriptování.

Vítejte :-)