Showing posts with label vbscript. Show all posts
Showing posts with label vbscript. Show all posts

Saturday, August 11, 2012

PowerShell: Use VBScript to Color Table Rows

I decided to take a break from the XML solutions for HTML management of multi-table reports in PowerShell.  This week I will demonstrate an extremely simple method that most Admin scripters can master because it uses the old standby “VBScript” to do the color tagging in the browser.

We use the same method to generate a table and create the HTML:

Param(
$reportpath
}
Get-WmiObject win32_logicaldisk |
Select-Object @{N='Server';E={$_.__SERVER}},
Deviceid,
@{N='PercentFree';E={[math]::Round($_.Freespace/$_.Size * 100,0)}} | ConvertTo-Html | Out-File $reportpath
&$reportpath

Same report.  Same HTML.

We can colorize the rows very easily by injecting some VBScript into the output file.

$head=@"
<script language="
vbscript">
Sub window_onload()
Set tbl1 = document.getElementsByTagName("
table")(0)
For Each r In tbl1.Rows
Set cell = r.lastChild
if IsNumeric(cell.innerText) Then
If cell.innerText < $threshold Then
cell.style.color="
red"
Else
cell.style.color="
green"
End If
Else
If LCase(cell.tagName) <> "
th" Then
cell.innerText="
n/a"
End If
End If
Next
End Sub
</script>
"
@

The above is just a “here-string”  wrapped around a block of VBScript.  You can put the script into the output file manually to see it work.  I built and tested the script in an HTA in about 5 minutes.

The VBScript is just a “window_onload” event that grabs first the table on the page and goes through each row in a for loop.

Set tbl1 = document.getElementsByTagName("table")(0)
For Each r In tbl1.Rows
Set cell = r.lastChild
If IsNumeric(cell.innerText) Then
If cell.innerText < 10 Then
cell.style.color="red"
Else
cell.style.color="green"
End If
Else
If LCase(cell.tagName) <> "th" Then
cell.innerText="n/a"
End If
End If
Next

Note how we skip the header cells and how I test for the existence of a numeric value.  For each row I get the last child of the row which I know is the column with the numbers. All columns are tested against a value that tells us when to color the column red.  We could also color the whole row by using cell.parent.style=”red”.  We might even set the background color.

Here is a copy of the test file: Copy and run it to see that it works.

<html>
<head>
<script language="vbscript">
   1:  
   2:     Sub window_onload()
   3:         Set tbl1 = document.getElementsByTagName("table")(0)
   4:         For Each r In tbl1.Rows
   5:             Set cell = r.lastChild 
   6:             if IsNumeric(cell.innerText) Then
   7:                 If cell.innerText < 10 Then
   8:                     cell.style.color="red"
   9:                 Else
  10:                     cell.style.color="green"
  11:                 End If
  12:             Else
  13:                 If LCase(cell.tagName) <> "th" Then
  14:                     cell.innerText="n/a"
  15:                 End If
  16:             End If
  17:         Next
  18:     End Sub
</script>
</head>
<body>
<table>
<colgroup>
<col/>
<col/>
<col/>
</colgroup>
<tr><th>Server</th><th>Deviceid</th><th>PercentFree</th></tr>
<tr><td>OMEGA2</td><td>A:</td><td></td></tr>
<tr><td>OMEGA2</td><td>C:</td><td>2</td></tr>
<tr><td>OMEGA2</td><td>D:</td><td></td></tr>
<tr><td>OMEGA2</td><td>E:</td><td>87</td></tr>
<tr><td>OMEGA2</td><td>F:</td><td>89</td></tr>
<tr><td>OMEGA2</td><td>X:</td><td>60</td></tr>
</table>
</body>
</html>

Once I had this working I just copied the script tag to my PowerShell editor and wrapped it in a here-string.  I also added a variable in place of the hard coded match variable.

Combining all the pieces we get this very simple PowerShell script.

<#
Create-DrivespaceReport.ps1
#>
Param(
$threshold = 50,
$reportpath='\\omega2\test\DriveSpace.htm'
)

$head=@"
<style type="
text/css">
body{
background-color: antiquewhite;
}
h4{
font-style: italic;
}
table{
border-collapse:collapse;
background-color: LightGoldenRodYellow;
}
table td{
border: 1px solid black;
font-weight: thinner;
}
table th{

border: 1px solid black;
font-weight: bolder;
color: #00008B;
background-color: gold;
}
</style>
<script language="
vbscript">
Sub window_onload()
Set tbl1 = document.getElementsByTagName("
table")(0)
For Each r In tbl1.Rows
Set cell = r.lastChild
if IsNumeric(cell.innerText) Then
If cell.innerText < $threshold Then
cell.style.color="
red"
Else
cell.style.color="
green"
End If
Else
If LCase(cell.tagName) <> "
th" Then
cell.innerText="
n/a"
End If
End If
Next
End Sub
</script>
"
@
$precontent="<h4>Disk Usage Report for $([datetime]::today.ToLongDateString())</h4>"
# generate the table
gwmi win32_logicaldisk |
Select-Object @{N='Server';E={$_.__SERVER}},
Deviceid,
@{N='PercentFree';E={[math]::Round($_.Freespace/$_.Size * 100,0)}} |
ConvertTo-Html -head $head -PreContent $precontent | Out-File $reportpath

# page has been copied to a trusted share so the script will execute
&$reportpath


For the final version I threw in a simple style sheet along with the script to give the page some color.  Click the link below to see the final sample.
 
Here is a link to download it: Simple Dynamically Colored Table Script

Here is a link to a sample of the report: Sample Report

Other articles in the series on managing HTML reports from PowerShell.

PowerShell: Dynamically Color PosH Generated HTML:Part 1
PowerShell: Dynamically Color PosH Generated HTML:Part 2
PowerShell: Dynamically Color PosH Generated HTML:Part 3

Sunday, June 14, 2009

Scripting: Win32_Service – Change Account/Password

When using Win32_Service to change the service account and/or service account password the following needs to be understood.

StartName is an account name and not the name of the service which is Name for internal service short name and DisplayName for the full visible service name.  The account name MUST be specified when changing the password as it appears that both are always validated.  The only time a Null or empty password can be used is when setting the account to LocalService.  All unused arguments in VB or VBScript must be set to Null or you will get an error. 

Note that the account used must be an accessible account either local or AD and must have the "run as a service" permission or you will get an service account not valid error.  The password must be present but does not need to be correct as this is only checked on an account restart.  Restating the service will check the  password and use the new setting.  If you are just setting passwords then you will have a race condition.

It is more normal to create a new account with the new password and reset all services to the new account.  This will guarantee that you DO NOT have a race condition when setting multiple accounts as the old account can keep the old password until all services have been re-provisioned.

uploads/2491/WMIChangeService.vbs.txt

1 Function WMIChangeServiceAccount(sComputer,serviceName, account, password ) 2 Set wmi = GetObject("winmgmts:{impersonationLevel=impersonate}!\\" & sComputer & "\root\cimv2") 3 Set colServices = wmi.ExecQuery("Select * From Win32_Service Where Name = '" & serviceName & "'") 4 For Each oService in colServices 5 result = oService.Change(Null ,Null ,Null ,Null ,Null ,Null ,account , password) 6 If result <> 0 Then 7 Select Case result 8 Case 0 : msg = "Success" 9 Case 1 : msg = "Not Supported" 10 Case 2 : msg = "Access Denied" 11 Case 3 : msg = "Dependent Services Running" 12 Case 4 : msg = "Invalid Service Control" 13 Case 5 : msg = "Service Cannot Accept Control" 14 Case 6 : msg = "Service Not Active" 15 Case 7 : msg = "Service Request Timeout" 16 Case 8 : msg = "Unknown Failure" 17 Case 9 : msg = "Path Not Found" 18 Case 10 : msg = "Service Already Running" 19 Case 11 : msg = "Service Database Locked" 20 Case 12 : msg = "Service Dependency Deleted" 21 Case 13 : msg = "Service Dependency Failure" 22 Case 14 : msg = "Service Disabled" 23 Case 15 : msg = "Service Logon Failure" 24 Case 16 : msg = "Service Marked For Deletion" 25 Case 17 : msg = "Service No Thread" 26 Case 18 : msg = "Status Circular Dependency" 27 Case 19 : msg = "Status Duplicate Name" 28 Case 20 : msg = "Status Invalid Name" 29 Case 21 : msg = "Status Invalid Parameter" 30 Case 22 : msg = "Status Invalid Service Account" 31 Case 23 : msg = "Status Service Exists" 32 Case 24 : msg = "Service Already Paused" 33 Case Else : msg = "Not defined" 34 End Select 35 Wscript.StdErr.WriteLine "WMIChangeServiceAccount failed:" & msg 36 End If 37 Next 38 End Function 39 40 WMIChangeServiceAccount ".", "Browser", "domain\account", "newpassword" 41 42

"Browser" is the name of the service.  The display name is "Computer Browser".  These names are not interchangeable.  "Name" required the internal short name of the service.  You can change the code to use "DisplayName" as the filter.

PowerShell is much better for WMI as it can let us view elements quickly at the command line.

gwmi win32_service
will get all of the installed services
gwmi win32_service | select name
will give us all internal service names
gwmi win32_service -filter "name like 'b%'"
will filter all names that have "b" as a first letter.

Try this with vbscript of CMD.  It can be done but takes far longer to accomplish.

Here is the same password change coded in PowerShell:

gwmi win32_service -filter "name like 'bro%'"|%{$_.Change($null,$null,$null,$null,$null,$null,$null,"domain\account","newpw")}

The decode of the result could be added as an "Enum" extension to the PowerShell type system and we could also add a script to the class that would allow a method of "ChangePassword" that would just take a password.