Showing posts with label powershell resources. Show all posts
Showing posts with label powershell resources. Show all posts

Saturday, September 20, 2014

Import-Module to Load Custom DLL

Recently a question was raised on how to find and load a custom DLL on any system.  I noted that it can be easily done using Import-Module if we place the DLL in  folder in any of the profile modules folders.

Each installation of PowerShell has a local global "Modules" folder.  To find you local modules folder, if it has been created, do the following:

Split-Path $profile

This will display the default location for the local user profile.  Now we can list the folders to see if the "Modules" folder has been created.

image

We also have a number of other profiles that we can discover like this:

image

When we use Get-Module <module name> PowerShell searches automatically through all of these folders for a Modules folder and looks in each folder for a sub-folder with a matching name.  We can place a module in any of these profile's module's folders and it will be found.

To get the path to any modules folder just split the profile path as above and add +'\Modules' to the string.

Example:

$modulepath=(Split-Path $profile.AllUsersAllHosts)+'\Modules'
dir $modulepath

image

AllUserAllHosts is a merged view of all module paths.

Now we can build and store our DLLs and script modules in any one of these paths and it can be loaded by name alone using Import-Module.

Here is the code from the Example here: Example1 or just type HELP Add-Type –online and go down to example 1.

$source=@'
public class BasicTest{

public static int Add(int a, int b){
return (a + b);
}

public int Multiply(int a, int b){
return (a * b);
}
}
'
@

Add-Type -TypeDefinition $source
[BasicTest]::Add(4, 3)
$basicTestObject = New-Object BasicTest
$basicTestObject.Multiply(5, 2)


Copy and paste this into a PowerShell prompt to see that it works as in the online example.

Now we will create a simple DLL with this code.  First we need to  open a new PowerShell CLI prompt because we have already created that type and we cannot unload it in PowerShell 4 and earlier. To unload a module we must restart PowerShell.  Now paste the following into the new PowerShell console.

$source=@'
public class BasicTest{

public static int Add(int a, int b){
return (a + b);
}

public int Multiply(int a, int b){
return (a * b);
}
}
'
@


Same source but now we are going to use it to build a DLL on disk in out Modules folder.

Start by creating the module folder.

$modules=Split-Path $profile
$BasicTest=$modules+'\BasicTest'
New-Item –Path $BasicTest –Name BasicTest –ItemType Directory

This is what you will see:

image

Now we have just one more step to create out DLL.

Add-Type -TypeDefinition $source -OutputType Library -OutputAssembly "$output\BasicTest.dll"

Now lets see what we have.

Is there a module already loaded with that name?

Get-Module BasicTest

No. Nothing is returned.  Can we find the module by name?

Get-Module –List BasicTest

image


So let's import it and test it again.

image

And that is how to both create and load your custom DLL.  In a domain environment we can distribute extensions by just saving them in the global modules folder.

Monday, May 12, 2014

Extracting Strings from Event Records #1

With event records in the old formmat obtained by using PowerShell Get-EventLog we can extract the strings as an array.

Example #1: 

PS C:\scripts> Get-EventLog -LogName Security -InstanceId 4634 -Newest 1|
>>Select -expand ReplacementStrings
S-1-5-7
ANONYMOUS LOGON
NT AUTHORITY
0xac30fba
3

Notice there are 5 strings.  They are an array.  We can use them in a formatted query like this:

Example #2: 

PS C:\scripts> Get-EventLog -LogName Security -InstanceId 4634 -Newest 1|
>> Select @{N='AccountSID';E={$_.ReplacementStrings[0]}}
>>

AccountSID
----------
S-1-5-21-2768830276-2144858717-3390379511-1000

Or more:

Example #3: 

PS C:\scripts> Get-EventLog -LogName Security -InstanceId 4634 -Newest 1|
>>    Select @{N='AccountSID';E={$_.ReplacementStrings[0]}},
>>           @{N='Domain';E={$_.ReplacementStrings[1]}}
>>

AccountSID                                                  Domain
----------                                                  ------
S-1-5-7                                                     ANONYMOUS LOGON

It is really that simple.

Monday, September 02, 2013

PowerShell Reporting With XML– Part 1

With PowerShell we are able to easily generate HTML from objects and, with some amount of adjusting, publish presentable reports.  This post is not about html publishing from PowerShell.  It is about exporting information as XML and then using PowerShell to generate a conversion to another format using XSLT in numerous ways.

What is XSLT?

XSLT stands for eXtensible StyleSheet Language Transormation.  It is a declaritive XML extension.  XML is the “eXensible” in XML and XSL/XSLT.  XSL is the XML specification for the  language used to manipulate XML data.  It can manipulate any XML variation including XSL.

Background Definitions:

W3C:

W3Schools:

PowerShell and XML

There are numerous examples and tutorials on the web.  The above information I but a very small part of what is available so why add more information and tutorials?

PowerShell can an does natively consume and emit XML.  Under the covers Microsoft Windows consumes and emits XML nearly everywhere.  Nearly all tools and tool products for Windows are XML based to some degree.  PowerShell support files are all XML.

Given the amount of XML everywhere it should be easy to generate reports that are readable and printable using the XML, but, in PowerShell there are no tools for doing this.  We will build some simple tools that will makes access to this XML data much easier.

CovertTo-Xml – A Simple XML Generator

http://technet.microsoft.com/library/hh849889.aspx

This CmdLet takes an object and converts it to XML.  By default it converts all top level properties of any object.

Try it:

$xml=get-process | ConvertTo-Xml
$xml.Objects.Object.Property

This will show you how the object is constructed.  The basic wrapper looks like this:

<Objects>
     <Object>
       <Property ..../>
        <Property ..../>
    </Object>
    ...
</Objects>

What can we do with this?

PowerShell can convert this into any other format required very easily by treating it as a collection of objects.  We can also just turn it directly into a report that can be published on a web site or sent by email.  We can do this without manipulating strings or using the PowerShell ConvertTo-Html which has many limitations when we need to produce complex dynamic reports.  An XSLT will allow us to merge two powerful tools into a solution.

The Code

# generate XML
$xml=get-process | ConvertTo-Xml
$xml.Save("$pwd\processes.xml")
 
#transform to HTML report
$xslt=New-Object System.Xml.Xsl.XslCompiledTransform
$xslt.Load("$pwd\processes.xsl")
$xslt.Transform("$pwd\processes.xml","$pwd\processes.html") 

That is all of the code it takes to dump a collection of objects mand run a transform to produse an HTML report.

What is the Advantage?

The advantage is that we can dump as many collections of XML objects as we need in out report and run one transform – the same transform as above – just that few lines of code.

Yes.  We can add as many XML data dumps as we need to gather the data for our report or reports.  We can deign a reporting system that just runs simple data dumps and not have to be concerned about how the data can be combined. The data can be combined in PowerShell or dumped independently.  It all depends on what our reporting system needs to consume.  What we buy is that the reporting system does not have to be data smart.  It just has to consume and transform XML.

Other Advantages

There are almost an unlimited number of other advantages to using XML/XSLT as the presentation tool.  Here are a few:

  1. We can easily inject extra info like table name or report name.
  2. XML can be converted to almost any other format for use by external systems
  3. XSL can generate dynamic web pages.
  4. XML can be reused in different reports and different sections.
  5. XML can be used to generate tables and lists with collapsible elements
  6. ….More..

I am not recommending that all reporting should be done this way.  For many simple reports just dumping text or direct use of would be more convenient.  Your choice of XML will depend on what we discuss in the next few issues of this set of blog posts.

Sunday, September 01, 2013

PowerShell Reporting With XML– Part 2

In this part I will show how to inject the XSLT into the XML document so it can be directly viewed in a browser.  This is a very simple operation and takes almost no code.

How to inject an XSLT reference into an XML file

.First we generate of load XML into an XML object:

$xmlfile="$pwd\services.xml"
$xml=gwmi win32_service | ConvertTo-Xml
$xml.Save($xmlfile)
. $xmlfile

This should open a browser and display XML assuming the browser you use is capable of this.  All currentversions of IE candispaly native XML.

You should see something like this:

image

Notice that each object is wrapped in a set of tags <Object> and eachproperty is called out in detail.  We only need two things from this.  We need the path to the object and the path to the text node of the property.

To get the objects in a list we can just query for them.  In PowerShell that query looks like this:

$xml.SelectNodes('//Objects/Object').Property|select name, '#text'

This produces a list of property names and values.  In XSLT we will do the same thing but we will do it in the browser using XSLT.

Enabling XSLT in the Browser

Here I the code that enables the XSLT in the browser:

# generate xml of objects
$xmlfile="$pwd\services.xml"
$xml=gwmi win32_service | ConvertTo-Xml
 
# inject an XSLT processing instrinction into the XML
$pi=$xml.CreateProcessingInstruction('xml-stylesheet', 'type="text/xsl" href="services.xsl"')
$xml.InsertBefore($pi,$xml.DocumentElement)
 
# save and launch in default browser
$xml.Save($xmlfile)
. $xmlfile

Of course we don’t yet have a XSL file so we will get only raw text output which is the default for a missing XSL file.

Here is a simple XSL file.  Copy and save it as “services.xsl” in the folder where you are testing this.  Currently the code uses the $pwd variable to find the current folder. Create a new folder so you can find the files more easily.  Make the new folder your current PowerShell folder.

<?xml version="1.0"?>
<xsl:stylesheet version="1.0"
    xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
 
     <xsl:template match="/">
       <html>
       <body>
           <xsl:apply-templates/>
       </body>
       </html>
     </xsl:template>
</xsl:stylesheet>

This is about the most fundamental XSL we can get for generating HTML.  It has one template and one “apply-templates”  instruction.  Create the file and rerun the code snippet.  YOu can actually just rerun the command to open in the browser:

. $xmlfile

How XSL Loops Through Data

Not much different but we can now demo how the XSL loops through data and generates HTML output.

Now copy this into your “services.xsl” file by replacing all text with this text:

<?xml version="1.0"?>
<xsl:stylesheet version="1.0"
    xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
 
     <xsl:template match="/">
       <html>
       <body>
           <xsl:apply-templates/>
       </body>
       </html>
     </xsl:template>
     
     <xsl:template match="Objects">
         <xsl:for-each select="Object">
             <p style="color: red;">Hello from Template</p>
         </xsl:for-each>
     </xsl:template>
</xsl:stylesheet> 
 

I have added another template and inserted some output.  The template selects ‘Object’ which says that whenever a tag of that name is found we should apply this template.  Inside the template we have an XSL  “for-each” instruction which says that for each of the selected tags (Object) we should perform the contents of the “for-each” block.  Inside of the “for-each” I have placed a simple HTML tag “<P>”

<p style="color: red;">Hello from for--each</p>

The style is set so we can show that all HTML is legal here.  The output now shows one red line for each object found.

Now this is pretty useless.  We should be outputting something useful so change the <p> line to this:

<p style="color: red;">
        <xsl:value-of select="Property[@Name='DisplayName']"/
</p>

If you make a mistake in the closure the display will default back to listing all text because of a processing error in the transform so be careful to make the change without disrupting the structure.

All tags in XML must be closed.  You cannot ignore this or bad things will happen. If we are injecting HTML into a transform it also has to be closed.

<tagname/>  - self closing
<tagname></tagname> – explicit closure
<tagname>Hello<newtag>…ILLEGAL

Notice that we have now created a paragraph with the DisplayName of the service in red.

Now lets make a table.  Replace the XSL with this:

<?xml version="1.0"?>
<xsl:stylesheet version="1.0"
    xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
 
     <xsl:template match="/">
       <html>
       <body>
           <xsl:apply-templates/>
       </body>
       </html>
     </xsl:template>
     
     <xsl:template match="Objects">
     
       <table border="1">
         <thead>
         <tr>
           <th>Display Name</th>
         </tr>
         </thead>
 
         <xsl:for-each select="Object">
            <tr>
                <td><xsl:value-of select="Property[@Name='DisplayName']"/></td>
            </tr>
         </xsl:for-each>
         
        </table>
        
     </xsl:template>
</xsl:stylesheet> 
 

Now we have a simple table with one column.  Note that we have injected the header on entry into the template but before we enumerate the “Object” collection.  In the “for-each” we emit the table rows.

Try it:

Now place a few more items of interest into the table.  Be careful. XML and XSL are case sensitive. All tags and all XPath expressions must respect the case of the names.  “displayname” and “DisplayName” are not the same.  You must match the case of the tags and attributes as well as the match case of the values being references.

Every bit of this line is case sensitive. If you change the case of any character the line will either fail or cause a syntax error.

<xsl:value-of select="Property[@Name='DisplayName']"/>

A More Complete Table

<?xml version="1.0"?>
<xsl:stylesheet version="1.0"
    xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
 
     <xsl:template match="/">
       <html>
       <body>
           <xsl:apply-templates/>
       </body>
       </html>
     </xsl:template>
     
     <xsl:template match="Objects">
     
       <table border="1">
         <thead>
         <tr>
           <th>Display Name</th>
           <th>Started</th>
           <th>Start Mode</th>
           <th>Description</th>
        </tr>
         </thead>
 
         <xsl:for-each select="Object">
            <tr>
                <td><xsl:value-of select="Property[@Name='DisplayName']"/></td>
                <td><xsl:value-of select="Property[@Name='Started']"/></td>
                <td><xsl:value-of select="Property[@Name='StartMode']"/></td>
                <td><xsl:value-of select="Property[@Name='Description']"/></td>
            </tr>
         </xsl:for-each>
         
        </table>
        
     </xsl:template>
</xsl:stylesheet> 
 

Now we have four columns and good information.  Perhaps now is a good time to take a look at the source of this page.  In the browser right click on the page and select “View Source”.  What do you see?  Why is there no HTML?  Can you see the injected processing instruction?

So browsers consume XML natively. They look at it just like it and follow the instructions.  In our case the instructions are to convert the XML for display.

In ‘Part 1’ we generated HTML output from a transform.  In this part we are only generating HTML.  The browser is taking care of the rest.

Adding CSS Style

We can style this table to make it ore readable and prettier by adding one line to our XSLT.

Create a file called services.css.  Add the following content:

body{
    background-color: bisque;
}
 
thead{
    background-color: #9acd32;
}
 
table{
    border-collapse: collapse;
}

Now add this line to the XSL file.

<link href="services.css" rel="stylesheet" type="text/css"/>

Here is the complete XSL:

<?xml version="1.0"?>
<xsl:stylesheet version="1.0"
    xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
 
     <xsl:template match="/">
       <html>
       <link href="scripts.css" rel="stylesheet" type="text/css"/>
       <body>
           <xsl:apply-templates/>
       </body>
       </html>
     </xsl:template>
     
     <xsl:template match="Objects">
     
       <table border="1">
         <thead>
         <tr>
           <th>Display Name</th>
           <th>Started</th>
           <th>Start Mode</th>
           <th>Description</th>
        </tr>
         </thead>
 
         <xsl:for-each select="Object">
            <tr>
                <td><xsl:value-of select="Property[@Name='DisplayName']"/></td>
                <td><xsl:value-of select="Property[@Name='Started']"/></td>
                <td><xsl:value-of select="Property[@Name='StartMode']"/></td>
                <td><xsl:value-of select="Property[@Name='Description']"/></td>
            </tr>
         </xsl:for-each>
         
        </table>
        
     </xsl:template>
</xsl:stylesheet> 
 

Now you should see the XML with some basic formatting for easier reading.  We can use the CSS to do all manner of custom formatting.

That is enough for this part.  In the next part I will investigate more formatting and layout options as well as using PowerShell to add extra info such as the table name and the page title.

For all links to this series use this tag: PowerShell Reporting(XML)