Skip to content

Instantly share code, notes, and snippets.

Embed
What would you like to do?
NAME
C:\Users\Jim\desktop\RWExport\PowerShell\Version 0.8a\RWExport-To-HTML.ps1
SYNOPSIS
RWExport-To-HTML.ps1
by EightBitz
Version 0.8a
2017-01-24, 05:00 AM CST
RWExport-To-HTML.ps1 transforms a Realm Works export file into a formatted HTML file. The formatted HTML file
relies on a "main.css" file for formatting information.
LICENSE:
This script is now licensed under the Creative Commons Attribution
Basically, that means:
-You are free to share and adapt the script.
-When sharing the script, you must give appropriate credit and indicate if changes were made.
-You may not use the material for commercial purposes.
Summary: https://creativecommons.org/licenses/by/4.0/
Legal Code: https://creativecommons.org/licenses/by/4.0/legalcode
IMPORTANT:
You will likely have to change your execution policy to run this script. You can do that with the following
command:
Set-ExecutionPolicy RemoteSigned
You may have to be logged in as a local administrator to do this, or run at least use the "Run as Administrator"
option when opening PowerShell (you can do this with a right-click).
Please do NOT set the execution policy to "Unrestricted". If you still have issues after setting it to
"RemoteSigned", then you can open this script as a text file, select all, copy, and paste it into a new text file.
Once you do that, delete the old file, and rename the new one to "RWExport-To-HTML.ps1".
IMPORTANT:
The export from Realm Works must done with the "Compact Output" option. This script will likely not work with a
"Full Export".
You can still export your full realm if you like, but make sure you do so with the "Compact Output" option.
IMPORTANT:
Make sure that the HTML file and the main.css file are in the same directory, otherwise, the HTML file will have
no formatting.
For more information about this, type:
Get-Help .\RWExport-To-HTML.ps1 -full
And see the NOTES section.
SYNTAX
C:\Users\Jim\desktop\RWExport\PowerShell\Version 0.8a\RWExport-To-HTML.ps1 [-Source] <String> [-Destination]
<String> [-Sort <Int32>] [-Prefix] [-Suffix] [-Details] [-Indent] [-SeparateSnippets] [-InlineStats]
[-SimpleImageScale <Int32>] [-SmartImageScale <Int32>] [-KeepStyles] [-CSSFileName <String>] [-Log <String>]
[<CommonParameters>]
DESCRIPTION
RWExport-To-HTML.ps1 loads the XML file exported from Realm Works and transforms it into formatted HTML so it can
be printed or imported/pasted into other programs. The export from Realm Works must done with the Compact Output
option.
PARAMETERS
-Source <String>
Enter the full path and filename for the source file (the Realm Works export file).
IMPORTANT: This must be the first parameter on the command line.
Required? true
Position? 2
Default value
Accept pipeline input? false
Accept wildcard characters? false
-Destination <String>
Enter the full path and filename for the destination file (the HTML output).
IMPORTANT: This must be the second parameter on the command line.
(As long as the source and destination parameters are the first two, the remaining parameters are optional and
can be used in any order.)
Required? true
Position? 3
Default value
Accept pipeline input? false
Accept wildcard characters? false
-Sort <Int32>
Choose your preferred sort order for exported topics.
1 = Name
2 = Prefix, Name **Default**
3 = Category, Name
4 = Category, Prefix, Name
Required? false
Position? named
Default value 2
Accept pipeline input? false
Accept wildcard characters? false
-Prefix [<SwitchParameter>]
Include this parameter to display the prefix for each topic. If you've entered prefixes for your topics in
Realm Works, this option will add them to the display in the HTML file in the form of "Prefix - Topic Name".
Required? false
Position? named
Default value False
Accept pipeline input? false
Accept wildcard characters? false
-Suffix [<SwitchParameter>]
Include this parameter to display the suffix for each topic. If you've entered suffixes for your topics in
Realm Works, this option will add them to the display in the HTML file in the form of "Topic Name (Suffix)".
If you include both the Prefix and Suffix parameters, the result will be "Prefix - Topic Name (Suffix)".
Required? false
Position? named
Default value False
Accept pipeline input? false
Accept wildcard characters? false
-Details [<SwitchParameter>]
Include this parameter to include topic details (Category, Parent, Linkage, Tags, etc ...)
Required? false
Position? named
Default value False
Accept pipeline input? false
Accept wildcard characters? false
-Indent [<SwitchParameter>]
Include this parameter to indent nested topics and section headers.
Required? false
Position? named
Default value False
Accept pipeline input? false
Accept wildcard characters? false
-SeparateSnippets [<SwitchParameter>]
Include this parameter to display a line between snippets.
Required? false
Position? named
Default value False
Accept pipeline input? false
Accept wildcard characters? false
-InlineStats [<SwitchParameter>]
Display Statblocks inline.
Required? false
Position? named
Default value False
Accept pipeline input? false
Accept wildcard characters? false
-SimpleImageScale <Int32>
Include this parameter to scale the display size, by percentage, of embedded simple pictures.
If you omit this parameter or if you set it to 0, only the thumbnail will display.
Required? false
Position? named
Default value 0
Accept pipeline input? false
Accept wildcard characters? false
-SmartImageScale <Int32>
Include this parameter to scale the display size, by percentage, of embedded smart images (usually maps).
If you omit this parameter or if you set it to 0, only the thumbnail will display.
Required? false
Position? named
Default value 0
Accept pipeline input? false
Accept wildcard characters? false
-KeepStyles [<SwitchParameter>]
By default, this script strips some (not all) formatting from the imported data. It does this to allow
formatting to be controlled by the the CSS file. Otherwise, the inline formatting will override the settings
in the CSS file.
If you want to keep the original formatting, though, you can use this option.
Right now, the format options that are stripped are: font, font size, font color and background color.
Note that the CSS file has different definitions for regular snippet text, bulleted lists, numbered lists and
tables.
Required? false
Position? named
Default value False
Accept pipeline input? false
Accept wildcard characters? false
-CSSFileName <String>
By default, the HTML output file looks for "main.css" to define its style. You can use this option to specify
a different name.
If you have two realms called Realm1 and Realm2, and you want each HTML output to have different fonts, font
sizes or colors, you can specify a name or "realma.css" for one file and "realmb.css" for the other.
Not that this option does not create the file. It just tells the HTML file which filename to look for.
For now, at least, you will have to manually copy main.css or some other css file you like and make whatever
changes you wish.
Required? false
Position? named
Default value main.css
Accept pipeline input? false
Accept wildcard characters? false
-Log <String>
Specify the path for an optional log file.
[NOT WORKING YET]
Required? false
Position? named
Default value
Accept pipeline input? false
Accept wildcard characters? false
<CommonParameters>
This cmdlet supports the common parameters: Verbose, Debug,
ErrorAction, ErrorVariable, WarningAction, WarningVariable,
OutBuffer, PipelineVariable, and OutVariable. For more information, see
about_CommonParameters (http://go.microsoft.com/fwlink/?LinkID=113216).
INPUTS
The .rwexport file from a Realm Works export that was created with the "Compact Output" option. This can an export
of a full realm or a custom or partial export, just so long as it's made with the "Compact Output" option.
OUTPUTS
An HTML file that uses an external style sheet for formatting. The external style sheet should be named "main.css"
and should be in the same folder as the HTML output. The main.css file will not be generated by this script, but
should already exist.
NOTES
SORTING:
The specified sort order will occur regardless of whether or not prefixes are included.
If you sort by prefix, but do not include the -Prefix parameter, your topics will still be sorted by prefix,
even though the prefix won't be displayed.
Likewise, if you sort by Name, but do include the -Prefix parameter, your topics will still be sorted by name,
even though the prefix will be displayed.
It appears that topics will always be sorted under their containers. In other words, topics that are not in
containers will be sorted relative to each other. Contained topics will be sorted relative to their peers
within that container.
TIPS ON MANAGING COMMANDLINE OPTIONS:
There are a several commandline options for this script, and that can probably be intimidating to some people.
Here is my recommended starting point:
c:\<full path>\RWExport-To-HTML.ps1 -Source C:\<full path>\MyExport.rwoutput -Destination c:\<full
path>\MyHTML.html -Indent -Prefix -Suffix -Sort 2
2 is the default sort value, so if that's what you want, you don't have to specify it, but I'm doing so anyway
just to be clear as to what's happening in this example.
If you like the output from this combination of options, you don't have to rememeber to type this out all the
time. You can save it as it's own PowerShell script. Paste the command into it's own .ps1 file. Name it
something like "MyExportOptions.ps1". (Make sure to replace <full path> with the actual path for where the
relevant files are.)
But you don't have to stop there. Say you have three different realms, and you want to specify different
options for each. You can do something like this:
c:\<full path>\RWExport-To-HTML.ps1 -Source C:\<full path>\Pathfinder-Realm.rwoutput -Destination c:\<full
path>\Pathfinder-Realm.html -Indent -Prefix -Suffix -Sort 2
c:\<full path>\RWExport-To-HTML.ps1 -Source C:\<full path>\SavageWorlds-Realm.rwoutput -Destination
c:\<full path>\SavageWorlds-Realm.html -Indent -InlineStats
c:\<full path>\RWExport-To-HTML.ps1 -Source C:\<full path>\FATE-Realm.rwoutput -Destination c:\<full
path>\FATE-Realm.html -SimpleImageScale 25 -SmartImageScale 50
You can put all three of those command lines in the same PowerShell script and call it
"ConvertAllMyExports.ps1".
Or you can put each command line in its own script called "ConvertPathfinderExport.ps1",
"ConvertSavageWorldsExport.ps1" and "ConvertFATEExport.ps1"
Now, when you want convert a given export, you don't have to remember all the command line options, because
you already have your favorite ones ready to go. You just run your PowerShell script instead of this one, and
yours will invoke this one with your favorite options.
As a side note, you can set up a separate folder for each export, and put a different main.css file in each
folder, so you can give each export a completely different look (by editing the main.css file in each folder).
AND SPEAKING OF MAIN.CSS:
This script and its resulting HTML file assume the existence of a file named "main.css". If this file is not
in the same folder as the resulting HTML file, it will not display correctly.
-------------------------- EXAMPLE 1 --------------------------
PS C:\>RWExport-To-HTML.ps1 -Source MyExport.rwoutput -Destination MyHTML.html
This is the most basic example.
This would give you the most basic output. The text would be formatted according to Title, Topic, Section and
Snippet, and that's about it. Nothing much more than that.
Topics will be sorted by prefix first, then by name.
Topics will be listed by name only with no prefixes or suffixes.
Nested topics and sections will not be indented. Everything will be left-justified.
Statblocks will not be displayed inline.
Simple Pictures and Smart Images will be displayed as thumbnails.
-------------------------- EXAMPLE 2 --------------------------
PS C:\>RWExport-To-HTML.ps1 -Source MyExport.rwoutput -Destination MyHTML.html -Sort 1
Choose your preferred sort order for exported topics. The example above will sort topics by their names.
Valid options are:
1 = Sort by topic names
2 = Sort by topic prefixes first, then by topic names (this is the default value)
3 = Sort by topic category first, then by topic name
4 = Sort by topic category first, then by topic prefix, then by topic name
-------------------------- EXAMPLE 3 --------------------------
PS C:\>RWExport-To-HTML.ps1 -Source MyExport.rwoutput -Destination MyHTML.html -Prefix
Prepend topic prefixes to topic names.
If a topic has a prefix of "Dungeon 1" and a name of "Room 3", you would include the Prefix parameter to list the
topic in the output as "Dungeon 1 - Room 3"
-------------------------- EXAMPLE 4 --------------------------
PS C:\>RWExport-To-HTML.ps1 -Source MyExport.rwoutput -Destination MyHTML.html -Suffix
Append topic suffixes to topic names.
If a topic has a suffix of "Mess Hall" and a name of "Room 3", you would include the Suffix parameter to list the
topic in the output as "Room 3 (Mess Hall)"
If you include the prefix and suffix parameter, the topic would be displayed as "Dungeon 1 - Room 3 (Mess Hall)"
-------------------------- EXAMPLE 5 --------------------------
PS C:\>RWExport-To-HTML.ps1 -Source MyExport.rwoutput -Destination MyHTML.html -Indent
To give your output just a little more style, you can choose to indent subsections and contained topics.
This looks really nice for documents that have content that might be nested 2 or 3 levels in, but for documents
that might have 4, 5 or 6 levels of nested topics and subsections, it might not look so great.
-------------------------- EXAMPLE 6 --------------------------
PS C:\>RWExport-To-HTML.ps1 -Source MyExport.rwoutput -Destination MyHTML.html -InlineStats
By default, stat blocks will not display inline, but will instead offer a clickable link where you can then see
the full stat block.
If you want everything in one view, though, without having to click, you can use the -InlineStats option.
Inline stat blocks will not always look as nice as you might like, but this parameter gives you the option to
include them if you like.
Also, if you include both -Indent and -InlineStats, the stat blocks will NOT indent. That prospect was fraught
with too many headaches.
As far as "looking nice", the clickable links are the better option, but if you want everything viewable in one
document, this gives you that option.
-------------------------- EXAMPLE 7 --------------------------
PS C:\>RWExport-To-HTML.ps1 -Source MyExport.rwoutput -Destination MyHTML.html -SimpleImageScale 50
Display simple images inline at 50% of their full size.
-------------------------- EXAMPLE 8 --------------------------
PS C:\>RWExport-To-HTML.ps1 -Source MyExport.rwoutput -Destination MyHTML.html -SmartImageScale 50
Display smart images inline at 50% of their full size.
RELATED LINKS
<!DOCTYPE html>
<html><head>
<meta http-equiv="content-type" content="text/html; charset=UTF-8">
<title>Creative Commons — Attribution 4.0 International — CC BY 4.0</title>
<meta charset="UTF-8">
<link rel="stylesheet" type="text/css" href="Creative%20Commons%20%E2%80%94%20Attribution%204.0%20International%20%E2%80%94%20CC%20BY%204.0_files/deed3.css" media="screen">
<link rel="stylesheet" type="text/css" href="Creative%20Commons%20%E2%80%94%20Attribution%204.0%20International%20%E2%80%94%20CC%20BY%204.0_files/deed3-print.css" media="print">
<!--[if lt IE 7]><link rel="stylesheet" type="text/css" href="//creativecommons.org/includes/deed3-ie.css" media="screen" /><![endif]-->
<script type="text/javascript" src="Creative%20Commons%20%E2%80%94%20Attribution%204.0%20International%20%E2%80%94%20CC%20BY%204.0_files/errata.js"></script>
<style type="text/css">#deed-main a{font-weight:normal;}.shaded{background-color:#eeeeee;margin:15px 0;padding:8px;clear:both;}h3{margin-top:0;padding-left:0;}</style>
</head>
<body>
<p id="header"><a href="https://creativecommons.org/">Creative Commons</a></p>
<div id="deed" class="green">
<div id="deed-head">
<div id="cc-logo">
<img src="Creative%20Commons%20%E2%80%94%20Attribution%204.0%20International%20%E2%80%94%20CC%20BY%204.0_files/cc-logo.jpg" alt="CC">
</div>
<h1><span>Creative Commons Legal Code</span></h1>
<div id="deed-license">
<h2>Attribution 4.0 International</h2>
</div>
</div>
<div id="deed-main">
<div id="deed-main-content">
<img src="Creative%20Commons%20%E2%80%94%20Attribution%204.0%20International%20%E2%80%94%20CC%20BY%204.0_files/unported.png" alt="">
<div id="deed-disclaimer">
<div class="summary">
Official translations of this license are available <a href="#languages">in other languages</a>.
</div>
</div>
<div class="shaded">
<p>Creative Commons Corporation (“Creative Commons”) is not a law firm
and does not provide legal services or legal advice. Distribution of
Creative Commons public licenses does not create a lawyer-client or
other relationship. Creative Commons makes its licenses and related
information available on an “as-is” basis. Creative Commons gives no
warranties regarding its licenses, any material licensed under their
terms and conditions, or any related information. Creative Commons
disclaims all liability for damages resulting from their use to the
fullest extent possible.</p>
</div>
<div class="shaded">
<p><strong>Using Creative Commons Public Licenses</strong></p>
<p>Creative Commons public licenses provide a standard set of terms and
conditions that creators and other rights holders may use to share
original works of authorship and other material subject to copyright and
certain other rights specified in the public license below. The
following considerations are for informational purposes only, are not
exhaustive, and do not form part of our licenses.</p>
<blockquote><strong>Considerations for licensors:</strong> Our public
licenses are intended for use by those authorized to give the public
permission to use material in ways otherwise restricted by copyright and
certain other rights. Our licenses are irrevocable. Licensors should
read and understand the terms and conditions of the license they choose
before applying it. Licensors should also secure all rights necessary
before applying our licenses so that the public can reuse the material
as expected. Licensors should clearly mark any material not subject to
the license. This includes other CC-licensed material, or material used
under an exception or limitation to copyright. <a href="https://wiki.creativecommons.org/Considerations_for_licensors_and_licensees#Considerations_for_licensors">More considerations for licensors.</a></blockquote>
<blockquote><strong>Considerations for the public:</strong> By using one
of our public licenses, a licensor grants the public permission to use
the licensed material under specified terms and conditions. If the
licensor’s permission is not necessary for any reason–for example,
because of any applicable exception or limitation to copyright–then that
use is not regulated by the license. Our licenses grant only
permissions under copyright and certain other rights that a licensor has
authority to grant. Use of the licensed material may still be
restricted for other reasons, including because others have copyright or
other rights in the material. A licensor may make special requests,
such as asking that all changes be marked or described. Although not
required by our licenses, you are encouraged to respect those requests
where reasonable.
<a href="https://wiki.creativecommons.org/Considerations_for_licensors_and_licensees#Considerations_for_licensees">More considerations for the public.</a></blockquote>
</div>
<h3>Creative Commons Attribution 4.0 International Public License</h3>
<p>By exercising the Licensed Rights (defined below), You accept and
agree to be bound by the terms and conditions of this Creative Commons
Attribution 4.0 International Public License ("Public License"). To the
extent this Public License may be interpreted as a contract, You are
granted the Licensed Rights in consideration of Your acceptance of these
terms and conditions, and the Licensor grants You such rights in
consideration of benefits the Licensor receives from making the Licensed
Material available under these terms and conditions.</p>
<p id="s1"><strong>Section 1 – Definitions.</strong></p>
<ol type="a">
<li id="s1a"><strong>Adapted Material</strong> means material subject to
Copyright and Similar Rights that is derived from or based upon the
Licensed Material and in which the Licensed Material is translated,
altered, arranged, transformed, or otherwise modified in a manner
requiring permission under the Copyright and Similar Rights held by the
Licensor. For purposes of this Public License, where the Licensed
Material is a musical work, performance, or sound recording, Adapted
Material is always produced where the Licensed Material is synched in
timed relation with a moving image.</li>
<li id="s1b"><strong>Adapter's License</strong> means the license You
apply to Your Copyright and Similar Rights in Your contributions to
Adapted Material in accordance with the terms and conditions of this
Public License.</li>
<li id="s1c"><strong>Copyright and Similar Rights</strong> means
copyright and/or similar rights closely related to copyright including,
without limitation, performance, broadcast, sound recording, and Sui
Generis Database Rights, without regard to how the rights are labeled or
categorized. For purposes of this Public License, the rights specified
in Section <a href="#s2b">2(b)(1)-(2)</a> are not Copyright and Similar Rights.</li>
<li id="s1d"><strong>Effective Technological Measures</strong> means
those measures that, in the absence of proper authority, may not
be circumvented under laws fulfilling obligations under Article 11 of
the WIPO Copyright Treaty adopted on December 20, 1996, and/or similar
international agreements.</li>
<li id="s1e"><strong>Exceptions and Limitations</strong> means fair use,
fair dealing, and/or any other exception or limitation to Copyright and
Similar Rights that applies to Your use of the Licensed Material.</li>
<li id="s1f"><strong>Licensed Material</strong> means the artistic or literary work, database, or other material to which the Licensor applied this Public License.</li>
<li id="s1g"><strong>Licensed Rights</strong> means the rights granted
to You subject to the terms and conditions of this Public License, which
are limited to all Copyright and Similar Rights that apply to Your use
of the Licensed Material and that the Licensor has authority to license.</li>
<li id="s1h"><strong>Licensor</strong> means the individual(s) or entity(ies) granting rights under this Public License.</li>
<li id="s1i"><strong>Share</strong> means to provide material to the
public by any means or process that requires permission under the
Licensed Rights, such as reproduction, public display, public
performance, distribution, dissemination, communication, or importation,
and to make material available to the public including in ways that
members of the public may access the material from a place and at a time
individually chosen by them.</li>
<li id="s1j"><strong>Sui Generis Database Rights</strong> means rights
other than copyright resulting from Directive 96/9/EC of the European
Parliament and of the Council of 11 March 1996 on the legal protection
of databases, as amended and/or succeeded, as well as other essentially
equivalent rights anywhere in the world.</li>
<li id="s1k"><strong>You</strong> means the individual or entity exercising the Licensed Rights under this Public License. <strong>Your</strong> has a corresponding meaning.</li>
</ol>
<p id="s2"><strong>Section 2 – Scope.</strong></p>
<ol type="a">
<li id="s2a"><strong>License grant</strong>.
<ol>
<li id="s2a1">Subject to the terms and conditions of this Public
License, the Licensor hereby grants You a worldwide, royalty-free,
non-sublicensable, non-exclusive, irrevocable license to exercise the
Licensed Rights in the Licensed Material to:
<ol type="A">
<li id="s2a1A">reproduce and Share the Licensed Material, in whole or in part; and</li>
<li id="s2a1B">produce, reproduce, and Share Adapted Material.</li>
</ol>
</li><li id="s2a2"><span style="text-decoration: underline;">Exceptions and Limitations</span>.
For the avoidance of doubt, where Exceptions and Limitations apply to
Your use, this Public License does not apply, and You do not need to
comply with its terms and conditions.</li>
<li id="s2a3"><span style="text-decoration: underline;">Term</span>. The term of this Public License is specified in Section <a href="#s6a">6(a)</a>.</li>
<li id="s2a4"><span style="text-decoration: underline;">Media and formats; technical modifications allowed</span>.
The Licensor authorizes You to exercise the Licensed Rights in all
media and formats whether now known or hereafter created, and to make
technical modifications necessary to do so. The Licensor waives and/or
agrees not to assert any right or authority to forbid You from making
technical modifications necessary to exercise the Licensed Rights,
including technical modifications necessary to circumvent Effective
Technological Measures. For purposes of this Public License, simply
making modifications authorized by this Section <a href="#s2a4">2(a)(4)</a> never produces Adapted Material.</li>
<li id="s2a5"><span style="text-decoration: underline;">Downstream recipients</span>.
<div class="para">
<ol type="A">
<li id="s2a5A"><span style="text-decoration: underline;">Offer from the Licensor – Licensed Material</span>.
Every recipient of the Licensed Material automatically receives an
offer from the Licensor to exercise the Licensed Rights under the terms
and conditions of this Public License.</li>
<li id="s2a5B"><span style="text-decoration: underline;">No downstream restrictions</span>.
You may not offer or impose any additional or different terms or
conditions on, or apply any Effective Technological Measures to, the
Licensed Material if doing so restricts exercise of the Licensed Rights
by any recipient of the Licensed Material.</li>
</ol>
</div>
</li><li id="s2a6"><span style="text-decoration: underline;">No endorsement</span>.
Nothing in this Public License constitutes or may be construed as
permission to assert or imply that You are, or that Your use of the
Licensed Material is, connected with, or sponsored, endorsed, or granted
official status by, the Licensor or others designated to receive
attribution as provided in Section <a href="#s3a1Ai">3(a)(1)(A)(i)</a>.</li>
</ol>
</li><li id="s2b"><p><strong>Other rights</strong>.</p>
<ol>
<li id="s2b1">Moral rights, such as the right of integrity, are not
licensed under this Public License, nor are publicity, privacy, and/or
other similar personality rights; however, to the extent possible, the
Licensor waives and/or agrees not to assert any such rights held by the
Licensor to the limited extent necessary to allow You to exercise the
Licensed Rights, but not otherwise.</li>
<li id="s2b2">Patent and trademark rights are not licensed under this Public License.</li>
<li id="s2b3">To the extent possible, the Licensor waives any right to
collect royalties from You for the exercise of the Licensed Rights,
whether directly or through a collecting society under any voluntary or
waivable statutory or compulsory licensing scheme. In all other cases
the Licensor expressly reserves any right to collect such royalties.</li>
</ol>
</li>
</ol>
<p id="s3"><strong>Section 3 – License Conditions.</strong></p>
<p>Your exercise of the Licensed Rights is expressly made subject to the following conditions.</p>
<ol type="a">
<li id="s3a"><p><strong>Attribution</strong>.</p>
<ol>
<li id="s3a1"><p>If You Share the Licensed Material (including in modified form), You must:</p>
<ol type="A">
<li id="s3a1A">retain the following if it is supplied by the Licensor with the Licensed Material:
<ol type="i">
<li id="s3a1Ai">identification of the creator(s) of the Licensed
Material and any others designated to receive attribution, in any
reasonable manner requested by the Licensor (including by pseudonym if
designated);</li>
<li id="s3a1Aii">a copyright notice;</li>
<li id="s3a1Aiii">a notice that refers to this Public License; </li>
<li id="s3a1Aiv">a notice that refers to the disclaimer of warranties;</li>
<li id="s3a1Av">a URI or hyperlink to the Licensed Material to the extent reasonably practicable;</li>
</ol>
</li><li id="s3a1B">indicate if You modified the Licensed Material and retain an indication of any previous modifications; and</li>
<li id="s3a1C">indicate the Licensed Material is licensed under this Public License,
and include the text of, or the URI or hyperlink to, this Public
License.</li>
</ol>
</li>
<li id="s3a2">You may satisfy the conditions in Section <a href="#s3a1">3(a)(1)</a>
in any reasonable manner based on the medium, means, and context in
which You Share the Licensed Material. For example, it may be reasonable
to satisfy the conditions by providing a URI or hyperlink to a resource
that includes the required information.</li>
<li id="s3a3">If requested by the Licensor, You must remove any of the information required by Section <a href="#s3a1A">3(a)(1)(A)</a> to the extent reasonably practicable.</li>
<li id="s3a4">If You Share Adapted Material You produce, the Adapter's
License You apply must not prevent recipients of the Adapted Material
from complying with this Public License.</li>
</ol>
</li>
</ol>
<p id="s4"><strong>Section 4 – Sui Generis Database Rights.</strong></p>
<p>Where the Licensed Rights include Sui Generis Database Rights that apply to Your use of the Licensed Material:</p>
<ol type="a">
<li id="s4a">for the avoidance of doubt, Section <a href="#s2a1">2(a)(1)</a> grants You the right to extract, reuse, reproduce, and Share all or a substantial portion of the contents of the database;</li>
<li id="s4b">if You include all or a substantial portion of the database
contents in a database in which You have Sui Generis Database Rights,
then the database in which You have Sui Generis Database Rights (but not
its individual contents) is Adapted Material; and</li>
<li id="s4c">You must comply with the conditions in Section <a href="#s3a">3(a)</a> if You Share all or a substantial portion of the contents of the database.</li>
</ol>
For the avoidance of doubt, this Section <a href="#s4">4</a> supplements
and does not replace Your obligations under this Public License where
the Licensed Rights include other Copyright and Similar Rights.
<p id="s5"><strong>Section 5 – Disclaimer of Warranties and Limitation of Liability.</strong></p>
<ol style="font-weight: bold;" type="a">
<li id="s5a"><strong>Unless otherwise separately undertaken by the
Licensor, to the extent possible, the Licensor offers the Licensed
Material as-is and as-available, and makes no representations or
warranties of any kind concerning the Licensed Material, whether
express, implied, statutory, or other. This includes, without
limitation, warranties of title, merchantability, fitness for a
particular purpose, non-infringement, absence of latent or other
defects, accuracy, or the presence or absence of errors, whether or not
known or discoverable. Where disclaimers of warranties are not allowed
in full or in part, this disclaimer may not apply to You.</strong></li>
<li id="s5b"><strong>To the extent possible, in no event will the
Licensor be liable to You on any legal theory (including, without
limitation, negligence) or otherwise for any direct, special, indirect,
incidental, consequential, punitive, exemplary, or other losses, costs,
expenses, or damages arising out of this Public License or use of the
Licensed Material, even if the Licensor has been advised of the
possibility of such losses, costs, expenses, or damages. Where a
limitation of liability is not allowed in full or in part, this
limitation may not apply to You.</strong></li>
</ol>
<ol start="3" type="a">
<li id="s5c">The disclaimer of warranties and limitation of liability
provided above shall be interpreted in a manner that, to the extent
possible, most closely approximates an absolute disclaimer and waiver of
all liability.</li>
</ol>
<p id="s6"><strong>Section 6 – Term and Termination.</strong></p>
<ol type="a">
<li id="s6a">This Public License applies for the term of the Copyright
and Similar Rights licensed here. However, if You fail to comply with
this Public License, then Your rights under this Public License
terminate automatically.</li>
<li id="s6b">
<p>Where Your right to use the Licensed Material has terminated under Section <a href="#s6a">6(a)</a>, it reinstates:</p>
<ol>
<li id="s6b1">automatically as of the date the violation is cured, provided it is cured within 30 days of Your discovery of the violation; or</li>
<li id="s6b2">upon express reinstatement by the Licensor.</li>
</ol>
For the avoidance of doubt, this Section <a href="#s6b">6(b)</a> does not affect any right the Licensor may have to seek remedies for Your violations of this Public License.</li>
<li id="s6c">For the avoidance of doubt, the Licensor may also offer the
Licensed Material under separate terms or conditions or stop
distributing the Licensed Material at any time; however, doing so will
not terminate this Public License.</li>
<li id="s6d">Sections <a href="#s1">1</a>, <a href="#s5">5</a>, <a href="#s6">6</a>, <a href="#s7">7</a>, and <a href="#s8">8</a> survive termination of this Public License.</li>
</ol>
<p id="s7"><strong>Section 7 – Other Terms and Conditions.</strong></p>
<ol type="a">
<li id="s7a">The Licensor shall not be bound by any additional or different terms or conditions communicated by You unless expressly agreed.</li>
<li id="s7b">Any arrangements, understandings, or agreements regarding
the Licensed Material not stated herein are separate from and
independent of the terms and conditions of this Public License.</li>
</ol>
<p id="s8"><strong>Section 8 – Interpretation.</strong></p>
<ol type="a">
<li id="s8a">For the avoidance of doubt, this Public License does not,
and shall not be interpreted to, reduce, limit, restrict, or impose
conditions on any use of the Licensed Material that could lawfully be
made without permission under this Public License.</li>
<li id="s8b">To the extent possible, if any provision of this Public
License is deemed unenforceable, it shall be automatically reformed to
the minimum extent necessary to make it enforceable. If the provision
cannot be reformed, it shall be severed from this Public License without
affecting the enforceability of the remaining terms and conditions.</li>
<li id="s8c">No term or condition of this Public License will be waived
and no failure to comply consented to unless expressly agreed to by the
Licensor.</li>
<li id="s8d">Nothing in this Public License constitutes or may be
interpreted as a limitation upon, or waiver of, any privileges and
immunities that apply to the Licensor or You, including from the legal
processes of any jurisdiction or authority.</li>
</ol>
<p class="shaded">Creative Commons is not a party to its public
licenses. Notwithstanding, Creative Commons may elect to apply one of
its public licenses to material it publishes and in those instances will
be considered the “Licensor.” The text of the Creative Commons public
licenses is dedicated to the public domain under the <a href="https://creativecommons.org/publicdomain/zero/1.0/legalcode">CC0 Public Domain Dedication</a>.
Except for the limited purpose of indicating that material is shared
under a Creative Commons public license or as otherwise permitted by the
Creative Commons policies published at <a href="https://creativecommons.org/policies">creativecommons.org/policies</a>,
Creative Commons does not authorize the use of the trademark “Creative
Commons” or any other trademark or logo of Creative Commons without its
prior written consent including, without limitation, in connection with
any unauthorized modifications to any of its public licenses or any
other arrangements, understandings, or agreements concerning use of
licensed material. For the avoidance of doubt, this paragraph does not
form part of the public licenses.<br><br>
Creative Commons may be contacted at <a href="https://creativecommons.org/">creativecommons.org</a>.</p>
<p class="shaded"><a name="languages">Additional languages available</a>: <a href="https://creativecommons.org/licenses/by/4.0/legalcode.id">Bahasa Indonesia</a>, <a href="https://creativecommons.org/licenses/by/4.0/legalcode.de">Deutsch</a>, <a href="https://creativecommons.org/licenses/by/4.0/legalcode.nl">Nederlands</a>, <a href="https://creativecommons.org/licenses/by/4.0/legalcode.no">norsk</a>, <a href="https://creativecommons.org/licenses/by/4.0/legalcode.fi">suomeksi</a>, <a href="https://creativecommons.org/licenses/by/4.0/legalcode.sv">svenska</a>, <a href="https://creativecommons.org/licenses/by/4.0/legalcode.mi">te reo Māori</a>, <a href="https://creativecommons.org/licenses/by/4.0/legalcode.uk">українська</a>, <a href="https://creativecommons.org/licenses/by/4.0/legalcode.ja">日本語</a>. Please read the <a href="https://wiki.creativecommons.org/FAQ#officialtranslations">FAQ</a> for more information about official translations. </p>
</div>
</div>
<div id="deed-foot">
<p id="footer"><a href="https://creativecommons.org/licenses/by/4.0/">« Back to Commons Deed</a></p>
</div>
</div>
</body></html>
/* Beginning of main.css file
main.css file for RWExport-To-HTML.ps1
by EightBitz
Version 0.8a
2017-01-24, 05:00 AM CST
This file must accompany the resulting HTML file
as it defines the formatting of the HTML file.
If you know CSS, feel free to modify these definitions
To your liking.
*/
/* Title */
H1 {
font-weight:bold;
color:black;
letter-spacing:1pt;
word-spacing:2pt;
font-size:30px;
text-align:center;
font-family:helvetica, sans-serif;line-height:1;
margin:0px;
padding:10px;
}
/* Topic Name */
H2 {
font-weight:bold;
color:black;
background-color:#CCCCCC;
/* color:white;
background-color:teal; */
letter-spacing:1pt;
word-spacing:2pt;
font-size:25px;
text-align:left;
font-family:helvetica, sans-serif;line-height:1;
margin:0px;
padding:10px;
}
/* Topic Details (Category, Parent, Linkage, Tags, etc ...) */
H3 {
font-weight:normal;
font-family:helvetica, sans-serif;line-height:1;
font-size: 16px;
font-style:italic;
color:black;
background-color:#CCCCCC;
/* color:white;
background-color:blue; */
padding:10px;
}
/* Section Header */
H4 {
font-weight:normal;
text-decoration:underline;
font-family:helvetica, sans-serif;line-height:1;
font-size: 20px;
background:white;
color: black;
}
/* Snippet Text */
P {
font-family:helvetica, sans-serif;line-height:1;
font-size: 16px;
background:white;
color:black;
}
/* Bulleted Lists */
UL {
font-family:helvetica, sans-serif;line-height:1;
font-size: 16px;
background:white;
color:black;
}
/* Numbered Lists */
OL {
font-family:helvetica, sans-serif;line-height:1;
font-size: 16px;
background:white;
color:black;
}
/* Text in Tables */
TABLE TR TD P {
font-family:helvetica, sans-serif;line-height:1;
background:white;
color:black;
font-size:16px;
}
/* The following items are for displaying inline stat blocks. */
.StatBlockLink {
color:#0000FF;
background-color:transparent;
font-family:Tahoma;
font-size:12pt;
font-weight:normal;
font-style:normal;
text-decoration: underline;
}
.StatBlockSnippet {
color:#000000;
background-color:transparent;
font-family:Tahoma;
font-size:12pt;
font-weight:normal;
font-style:normal;
}
.StatBlockDefault {
text-align:left;
text-indent:0pt;
margin:0pt 0pt 0pt 0pt
}
.StatBlockBullet {
text-align:left;
text-indent:-7pt;
margin:0pt 0pt 0pt 7pt}
.StatBlockEnumerated {
text-align:left;
text-indent:-12pt;
margin:0pt 0pt 0pt 12pt
}
.StatBlock-td {
border-style:solid;
border-width: 1px;
border-color: #a9a9a9;
padding: 1.5pt 4pt;
}
.StatBlock-tr.naked td {border-style:none;}
.StatBlock-td.left {text-align:left;}
.StatBlock-td.center {text-align:center;}
.StatBlock-td.right {text-align:right;}
.StatBlock-p.footer {margin-left:0.75em;
text-indent: -0.75em;
margin-top: 0;
margin-bottom: 0;
}
.StatBlock-p.smallgap {margin: 3pt 0 0 0;}
.StatBlock-p.mediumgap {margin: 6pt 0 0 0;}
/* End of main.css file */
Release Notes for RWExport-To-HTML.ps1
by EightBitz
=====================================================
Version 0.8a (2017-01-24, 05:00 AM CST)
=====================================================
RWExportGUI.ps1:
I've put together another script that serves as a GUI front end for the main script.
The code for the GUI script was mostly borrowed and adapted. The original source had the following header:
########################################################################
# Code Generated By: SAPIEN Technologies PrimalForms (Community Edition) v1.0.8.0
# Generated On: 7/3/2011 11:35 AM
# Generated By: sean.kearney
########################################################################
Licensing:
RWExport-To-HTML.ps1 is now licensed under the Creative Commons Attribution license
(I'm removing the non-commercial restriction.)
Basically, that means:
-You are free to share and adapt the script.
-When sharing the script, you must give appropriate credit and indicate if changes were made.
Summary: https://creativecommons.org/licenses/by/4.0/
Legal Code: https://creativecommons.org/licenses/by/4.0/legalcode
New command line options:
-KeepStyles
-CSSFileName
By default, text formatting is partially stripped. This is done to allow more uniform controll of text formatting through the CSS file.
If you wish to preserve your original formatting, include -KeepStyles on your command line.
Right now, the affected formatting elements are: font, font size, font color and background color.
Other formatting (bold, italic, underline, etc) will be preserved.
If you want to define a different CSS filename for each export, you can do that now.
Include -CSSFileName on your command line, followed by the name of the file.
Note that this option does NOT create the file. It merely specifies in the header of the HTML output. You will have to copy the main.css file, and rename the copy accordingly.
Stat Blocks:
HTML stat blocks are now also controlled by CSS. I was able to figure how to strip the previously defined formatting without breaking all the other formatting.
Other CSS Changes:
Tables are newly stripped of the previously defined formatting as well.
A new section for tables has been added to the main.css file to accomodate.
Other Improvements:
Addressed a cosmetic issue where "Label:" and "Annotation:" were displaying when there was no accompanying text.
Now, if a label is empty, you won't see "Label:" on an otherwise empty line, and if an annotation is empty, you won't see "Annotation:" on an otherwise empty line.
Issues:
I looked into an issue where Wingdings characters were not displaying properly, only to find out that supporting Wingdings is not part of the HTML Standard.
There are unicode equivalents, but building that translation table, and parsing the XML code for where to place substititons is more work than I want to do right now, and I don't think it's going to be a common enough issue to make it worthwhile.
The logging option is still not really functional.
Bug Fixes:
It looks like the "Stream was not readable" error is indeed fixed. Since applying the fix in the last version, I have not seen it reappear.
=====================================================
Version 0.7a (2017-01-21, 06:40 AM CST)
=====================================================
Licensing:
This script is now licensed under the Creative Commons Attribution + Non-Commercial license.
Basically, that means:
-You are free to share and adapt the script.
-When sharing the script, you must give appropriate credit and indicate if changes were made.
-You may not use the material for commercial purposes.
Summary: https://creativecommons.org/licenses/by-nc/4.0/
Legal Code: https://creativecommons.org/licenses/by-nc/4.0/legalcode
New command line options:
-Details
-SeparateSnippets
Topic details (Category, Parent, Linkage, Tags, etc ...) are no longer included by default. The topic details are nice for reference, but the document looks more presentable without them. If you're planning to share or publish, you may not want them in there at all. However, if you do, you can use the -Details option to put them back in.
Some snippets are longer, and some are shorter. Some are grouped and some are not. If you want a visual separator to show where one snippet ends and another begins, you can use the -SeparateSnippets option.
stream was not readable
Stat Blocks:
Inline statblocks are a lot cleaner now. They display the way they're supposed to display.
For non-HTML stat blocks, you can change their formatting in the main.css file.
HTML stat blocks are an exception, because they have inline CSS formatting. At this point I am concerned about the unintended consequences of programmatically stripping that out, regardless of how good my intentions may be.
If I find a good way to include affet HTML stat blocks, I will make that change. That being said, HTML stat blocks display fine. They're just unaffected by changes in the CSS file.
The original font size for stat blocks was 9 points. I had to squint to read that, so in the main.css file, I changed it to 12. If you click the link for the stat block, you'll see it in its original form, and you'll see the difference. If you like it at 9 points, you can easily make that change in the main.css file.
Other CSS Changes:
I discovered that lists were not effected by the definition for regular snippets, so I added two new CSS definitions. One for bulleted lists and one for numbered lists
Other Improvements:
I added input validation and error checking to make sure that the script does not attempt to run with invalid options. If an input file cannot be read, or an output file cannot be written, or a sort value is out of range, the script will report the error and exit.
This is prelude for better error trapping overall and for proper logging of errors to aid in future troubleshooting and debugging. The error trapping and logging were what I was originally planning to include in this release, but one thing after another took hold, and I figured people would appreciate the new changes and functionality.
Bug fixes:
Fixed an issue where snippets that contain both GM directions and regular text were not being properly handled.
Fixed some superficial, but nagging bugs. If you previously got a stream of errors reporting that certain functions or methods could not be called on a null value, those should be fixed in this version.
For display purposes, I was appending a colon (:) to snippets that had labels that did not already end with a colon. I fixed an issue were the colon was showing up even if there was no text in the label.
I have hopefully fixed an intermittent "Stream was not readable" error. It looks like the fix worked, but since it was intermittent, I can't say for sure. All I can say is that I have not had the error since applying a suggested fix.
Get-Help:
I have updated the Get-Help info as well, so you can see all the available command line options, what they do, and some examples of how to use them.
To use Get-Help, open a PowerShell window, and CD to the folder where you've saved the script. Then type any one of the following commands:
Get-Help .\RWExport-To-HTML.ps1
Get-Help .\RWExport-To-HTML.ps1 -examples
Get-Help .\RWExport-To-HTML.ps1 -detailed
Get-Help .\RWExport-To-HTML.ps1 -full
Furthermore, you can send the results of any one of those commands to a text file.
Get-Help C:\<full path>\RWExport-To-HTML.ps1 -full > Full-Help-for-RWExport.txt
That will create the indicated text file that will contain the results of the Get-Help command, and you can just keep that handy somewhere.
=====================================================
Version 0.6a (2017-01-19, 04:40 AM CST)
=====================================================
SHOW ALL THE SNIPPETS:
Added at least a listing of all snippet types. If the snippet is there, you will at least see its name and type.
IMAGES:
Added support for displaying images. Thumbnails display by default, but you can display a larger view with two new command line options.
-SimpleImageScale 20
-SmartImageScale 75
These work by percentages. So with the above examples, simple pictures will display at 20% of their full size, and smart images at 75%.
In both cases, the image name will be followed by a clickable link to display the image in full size.
STAT BLOCKS:
Stat blocks can now be viewed. By default, there is a clickable link after the name. If you would prefer, there is an option to display stat blocks inline.
-InlineStats
It's not always going to look pretty, but it's there. The clickable links will usually display cleaner versions.
HELP! WHAT DO I DO! HELP!
I polished the Get-Help info. Any time you want to know what options are available and how they work, you can use the following commands:
Get-Help C:\<full path>\RWExport-To-HTML.ps1
Get-Help C:\<full path>\RWExport-To-HTML.ps1 -examples
Get-Help C:\<full path>\RWExport-To-HTML.ps1 -detailed
Get-Help C:\<full path>\RWExport-To-HTML.ps1 -full
Furthermore, you can send the results of any one of those commands to a text file.
Get-Help C:\<full path>\RWExport-To-HTML.ps1 -full > Full-Help-for-RWExport.txt
That will create the indicated text file that will contain the results of the Get-Help command, and you can just keep that handy somewhere.
=====================================================
Version 0.5a (RWExport-to-HTML.ps1)
=====================================================
These are the release notes for the HTML version.
Most everything is the same, which is why I'm including the previous release notes for the text version.
The differences here are:
The obvious: HTML formatting.
With the HTML formatting comes and added CSS file, main.css.
main.css should always be in the same folder as the HTML output, otherwise the output will not be properly formatted.
There is also now an -Indent option which, if invoked, will indent nested topics and sections.
If you lose your main.css file, see the sample below:
/* Beginning of main.css file */
/*
This file must accompany the resulting HTML file
as it defines the formatting of the HTML file.
If you know CSS, feel free to modify these definitions
To your liking.
*/
/* Title */
H1 {
font-weight:bold;
color:#000000;
letter-spacing:1pt;
word-spacing:2pt;
font-size:30px;
text-align:center;
font-family:helvetica, sans-serif;line-height:1;
margin:0px;
padding:10px;
}
/* Topic Name */
H2 {
font-weight:bold;
color:#000000;
background-color:#CCCCCC;
letter-spacing:1pt;
word-spacing:2pt;
font-size:25px;
text-align:left;
font-family:helvetica, sans-serif;line-height:1;
margin:0px;
padding:10px;
}
/* Topic Details (Category, Parent, Linkage ...)*/
H3 {
font-weight:normal;
font-family:helvetica, sans-serif;line-height:1;
font-size: 16px;
font-style: italic;
color: black;
background-color:#CCCCCC;
padding:10px;
}
/* Section Header */
H4 {
font-weight:normal;
text-decoration:underline;
font-family:helvetica, sans-serif;line-height:1;
font-size: 20px;
background: #ffffff;
color: black;
}
/* Snippet */
P {
font-family:helvetica, sans-serif;line-height:1;
font-size: 16px;
background: #ffffff;
color: black;
}
/* End of main.css file */
=====================================================
Version 0.5a
=====================================================
Added a -Prefix switch to optionally include a topic's prefix.
Added a -Suffix switch to optionally include a topic's suffix.
Added a -Sort option to sort topics by:
1 = Name
2 = Prefix, Name **Default**
3 = Category, Name
4 = Category, Prefix, Name
Choosing options 2 or 4 will sort by prefix, regardless of whether or not
the -Prefix switch is specified. Likewise, choosing options 1 or 3 will
sort by name, regardless of whether or not the -Prefix switch is specified.
Added parentage for topics.
Made the topic suffix parenthetical so it's consistent with the display in RW.
Better (I hope) parsing of snippets, and support for more types.
Supported snippet types include:
Text (Including lists and tables, but NOT including any formatting such as bold, italic, highlights, etc.)
GM Directions
Labeled Text
Tags
Calendar Date
Calendar Date Range
Numeric Value
Tags (MultiDomain)
Unsupported snippet types include:
** Picture (Simple)
** Smart Image (Map)
XX Statblock
XX Hero Lab Portfolio
Foreign Object
Any snippet types listed under "Documents and Media"
=====================================================
Version 0.01a
=====================================================
- I am not well-versed in translating XML via XLST or CSS, so I'm working with what I know, and right now, that's PowerShell. I know there are probably 50 different ways that this could have been done better, and I know that there are a few people here who know all those ways, but alas, I'm stuck with what I know.
- In regards to the above, I'm not sharing this to impress anyone. I just want a simple, easy way to print, and I thought I would share this with anyone else who might want the same and who also isn't skilled with XLST and CSS.
- I'm mainly working on this for myself, because I want a way to print. If you like what you see, and you wish to request a change or a feature, I will do what I can, but understand that this is not my full-time job. In fact, I do not currently have a full-time job, nor any job, so my full-time job right now is to find a full-time job.
- This is a work in progress.
- I have tested multiple conditions, but only with small, simple exports.
- This will only process a compact export, not a full export. I'm not even going to mess with a full export.
- Right now, this is intended to process plain-text and tag-based snippets. It will not do anything with images, simple or smart. I have not tested how it handles tables or anything other than plain-text.
- The output, right now, is plain text. I would like to add CSS and HTML formatting, but right now, I wanted to get some basic functionality done first. And I still have to study up on CSS and HTML.
- The advantage with doing this through a procedural or scripting language is that I have finer control in what information to extract and how. The disadvantage is that it could take a while to run through a 5 GB realm. I'm not there yet, so I can't say for sure, though. But I'm guessing it will.
- I'm tired and I'm going to sleep. I hope this helps somebody. :-)
- Feel free to comment here or send me a PM, but just to preempt any questions of "Why did you do it this way when you could have done it this other and much better way?", the answer is, "Because this is the way I know how to do it."
<#
.SYNOPSIS
RWExport-To-HTML.ps1
by EightBitz
Version 0.8a
2017-01-24, 05:00 AM CST
RWExport-To-HTML.ps1 transforms a Realm Works export file into a formatted HTML file. The formatted HTML file relies on a "main.css" file for formatting information.
LICENSE:
This script is now licensed under the Creative Commons Attribution
Basically, that means:
-You are free to share and adapt the script.
-When sharing the script, you must give appropriate credit and indicate if changes were made.
-You may not use the material for commercial purposes.
Summary: https://creativecommons.org/licenses/by/4.0/
Legal Code: https://creativecommons.org/licenses/by/4.0/legalcode
IMPORTANT:
You will likely have to change your execution policy to run this script. You can do that with the following command:
Set-ExecutionPolicy RemoteSigned
You may have to be logged in as a local administrator to do this, or run at least use the "Run as Administrator" option when opening PowerShell (you can do this with a right-click).
Please do NOT set the execution policy to "Unrestricted". If you still have issues after setting it to "RemoteSigned", then you can open this script as a text file, select all, copy, and paste it into a new text file. Once you do that, delete the old file, and rename the new one to "RWExport-To-HTML.ps1".
IMPORTANT:
The export from Realm Works must done with the "Compact Output" option. This script will likely not work with a "Full Export".
You can still export your full realm if you like, but make sure you do so with the "Compact Output" option.
IMPORTANT:
Make sure that the HTML file and the main.css file are in the same directory, otherwise, the HTML file will have no formatting.
For more information about this, type:
Get-Help .\RWExport-To-HTML.ps1 -full
And see the NOTES section.
.DESCRIPTION
RWExport-To-HTML.ps1 loads the XML file exported from Realm Works and transforms it into formatted HTML so it can be printed or imported/pasted into other programs. The export from Realm Works must done with the Compact Output option.
.PARAMETER Source
Enter the full path and filename for the source file (the Realm Works export file).
IMPORTANT: This must be the first parameter on the command line.
.PARAMETER Destination
Enter the full path and filename for the destination file (the HTML output).
IMPORTANT: This must be the second parameter on the command line.
(As long as the source and destination parameters are the first two, the remaining parameters are optional and can be used in any order.)
.PARAMETER Sort
Choose your preferred sort order for exported topics.
1 = Name
2 = Prefix, Name **Default**
3 = Category, Name
4 = Category, Prefix, Name
.PARAMETER Prefix
Include this parameter to display the prefix for each topic. If you've entered prefixes for your topics in Realm Works, this option will add them to the display in the HTML file in the form of "Prefix - Topic Name".
.PARAMETER Suffix
Include this parameter to display the suffix for each topic. If you've entered suffixes for your topics in Realm Works, this option will add them to the display in the HTML file in the form of "Topic Name (Suffix)".
If you include both the Prefix and Suffix parameters, the result will be "Prefix - Topic Name (Suffix)".
.PARAMETER Details
Include this parameter to include topic details (Category, Parent, Linkage, Tags, etc ...)
.PARAMETER Indent
Include this parameter to indent nested topics and section headers.
.PARAMETER SeparateSnippets
Include this parameter to display a line between snippets.
.PARAMETER $InlineStats
Include this parameter to display full stat blocks inline. This won't always look pretty, but if you want the option, it's there.
Whether or not you include this parameter, a given stat block will always be available to view by clicking a hyperlink, and this will display it with its native formatting, so it will look like you would expect it to look.
.PARAMETER SimpleImageScale
Include this parameter to scale the display size, by percentage, of embedded simple pictures.
If you omit this parameter or if you set it to 0, only the thumbnail will display.
.PARAMETER SmartImageScale
Include this parameter to scale the display size, by percentage, of embedded smart images (usually maps).
If you omit this parameter or if you set it to 0, only the thumbnail will display.
.PARAMETER KeepStyles
By default, this script strips some (not all) formatting from the imported data. It does this to allow formatting to be controlled by the the CSS file. Otherwise, the inline formatting will override the settings in the CSS file.
If you want to keep the original formatting, though, you can use this option.
Right now, the format options that are stripped are: font, font size, font color and background color.
Note that the CSS file has different definitions for regular snippet text, bulleted lists, numbered lists and tables.
.PARAMETER CSSFileName
By default, the HTML output file looks for "main.css" to define its style. You can use this option to specify a different name.
If you have two realms called Realm1 and Realm2, and you want each HTML output to have different fonts, font sizes or colors, you can specify a name or "realma.css" for one file and "realmb.css" for the other.
Not that this option does not create the file. It just tells the HTML file which filename to look for.
For now, at least, you will have to manually copy main.css or some other css file you like and make whatever changes you wish.
.INPUTS
The .rwexport file from a Realm Works export that was created with the "Compact Output" option. This can an export of a full realm or a custom or partial export, just so long as it's made with the "Compact Output" option.
.OUTPUTS
An HTML file that uses an external style sheet for formatting. The external style sheet should be named "main.css" and should be in the same folder as the HTML output. The main.css file will not be generated by this script, but should already exist.
.EXAMPLE
RWExport-To-HTML.ps1 -Source MyExport.rwoutput -Destination MyHTML.html
This is the most basic example.
This would give you the most basic output. The text would be formatted according to Title, Topic, Section and Snippet, and that's about it. Nothing much more than that.
Topics will be sorted by prefix first, then by name.
Topics will be listed by name only with no prefixes or suffixes.
Nested topics and sections will not be indented. Everything will be left-justified.
Statblocks will not be displayed inline.
Simple Pictures and Smart Images will be displayed as thumbnails.
.EXAMPLE
RWExport-To-HTML.ps1 -Source MyExport.rwoutput -Destination MyHTML.html -Sort 1
Choose your preferred sort order for exported topics. The example above will sort topics by their names.
Valid options are:
1 = Sort by topic names
2 = Sort by topic prefixes first, then by topic names (this is the default value)
3 = Sort by topic category first, then by topic name
4 = Sort by topic category first, then by topic prefix, then by topic name
.EXAMPLE
RWExport-To-HTML.ps1 -Source MyExport.rwoutput -Destination MyHTML.html -Prefix
Prepend topic prefixes to topic names.
If a topic has a prefix of "Dungeon 1" and a name of "Room 3", you would include the Prefix parameter to list the topic in the output as "Dungeon 1 - Room 3"
.EXAMPLE
RWExport-To-HTML.ps1 -Source MyExport.rwoutput -Destination MyHTML.html -Suffix
Append topic suffixes to topic names.
If a topic has a suffix of "Mess Hall" and a name of "Room 3", you would include the Suffix parameter to list the topic in the output as "Room 3 (Mess Hall)"
If you include the prefix and suffix parameter, the topic would be displayed as "Dungeon 1 - Room 3 (Mess Hall)"
.EXAMPLE
RWExport-To-HTML.ps1 -Source MyExport.rwoutput -Destination MyHTML.html -Indent
To give your output just a little more style, you can choose to indent subsections and contained topics.
This looks really nice for documents that have content that might be nested 2 or 3 levels in, but for documents that might have 4, 5 or 6 levels of nested topics and subsections, it might not look so great.
.EXAMPLE
RWExport-To-HTML.ps1 -Source MyExport.rwoutput -Destination MyHTML.html -InlineStats
By default, stat blocks will not display inline, but will instead offer a clickable link where you can then see the full stat block.
If you want everything in one view, though, without having to click, you can use the -InlineStats option.
Inline stat blocks will not always look as nice as you might like, but this parameter gives you the option to include them if you like.
Also, if you include both -Indent and -InlineStats, the stat blocks will NOT indent. That prospect was fraught with too many headaches.
As far as "looking nice", the clickable links are the better option, but if you want everything viewable in one document, this gives you that option.
.EXAMPLE
RWExport-To-HTML.ps1 -Source MyExport.rwoutput -Destination MyHTML.html -SimpleImageScale 50
Display simple images inline at 50% of their full size.
.EXAMPLE
RWExport-To-HTML.ps1 -Source MyExport.rwoutput -Destination MyHTML.html -SmartImageScale 50
Display smart images inline at 50% of their full size.
.NOTES
SORTING:
The specified sort order will occur regardless of whether or not prefixes are included.
If you sort by prefix, but do not include the -Prefix parameter, your topics will still be sorted by prefix, even though the prefix won't be displayed.
Likewise, if you sort by Name, but do include the -Prefix parameter, your topics will still be sorted by name, even though the prefix will be displayed.
It appears that topics will always be sorted under their containers. In other words, topics that are not in containers will be sorted relative to each other. Contained topics will be sorted relative to their peers within that container.
TIPS ON MANAGING COMMANDLINE OPTIONS:
There are a several commandline options for this script, and that can probably be intimidating to some people. Here is my recommended starting point:
c:\<full path>\RWExport-To-HTML.ps1 -Source C:\<full path>\MyExport.rwoutput -Destination c:\<full path>\MyHTML.html -Indent -Prefix -Suffix -Sort 2
2 is the default sort value, so if that's what you want, you don't have to specify it, but I'm doing so anyway just to be clear as to what's happening in this example.
If you like the output from this combination of options, you don't have to rememeber to type this out all the time. You can save it as it's own PowerShell script. Paste the command into it's own .ps1 file. Name it something like "MyExportOptions.ps1". (Make sure to replace <full path> with the actual path for where the relevant files are.)
But you don't have to stop there. Say you have three different realms, and you want to specify different options for each. You can do something like this:
c:\<full path>\RWExport-To-HTML.ps1 -Source C:\<full path>\Pathfinder-Realm.rwoutput -Destination c:\<full path>\Pathfinder-Realm.html -Indent -Prefix -Suffix -Sort 2
c:\<full path>\RWExport-To-HTML.ps1 -Source C:\<full path>\SavageWorlds-Realm.rwoutput -Destination c:\<full path>\SavageWorlds-Realm.html -Indent -InlineStats
c:\<full path>\RWExport-To-HTML.ps1 -Source C:\<full path>\FATE-Realm.rwoutput -Destination c:\<full path>\FATE-Realm.html -SimpleImageScale 25 -SmartImageScale 50
You can put all three of those command lines in the same PowerShell script and call it "ConvertAllMyExports.ps1".
Or you can put each command line in its own script called "ConvertPathfinderExport.ps1", "ConvertSavageWorldsExport.ps1" and "ConvertFATEExport.ps1"
Now, when you want convert a given export, you don't have to remember all the command line options, because you already have your favorite ones ready to go. You just run your PowerShell script instead of this one, and yours will invoke this one with your favorite options.
As a side note, you can set up a separate folder for each export, and put a different main.css file in each folder, so you can give each export a completely different look (by editing the main.css file in each folder).
AND SPEAKING OF MAIN.CSS:
This script and its resulting HTML file assume the existence of a file named "main.css". If this file is not in the same folder as the resulting HTML file, it will not display correctly.
#>
param (
# Source file path and name.
[Parameter(Mandatory,Position=1)]
[string]$Source,
# Destination file path and name.
[Parameter(Mandatory,Position=2)]
[string]$Destination,
# Sort topics by:
# 1 = Name
# 2 = Prefix, Name **Default**
# 3 = Category, Name
# 4 = Category, Prefix, Name
#
# Choosing options 2 or 4 will sort by prefix, regardless of whether or not
# the -Prefix switch is specified. Likewise, choosing options 1 or 3 will
# sort by name, regardless of whether or not the -Prefix switch is specified.
[Parameter()]
[int]$Sort = 2,
# Include prefix in topic name ($true or $false)
[switch]$Prefix,
# Include suffix in topic name ($true or $false)
[switch]$Suffix,
# Include topic details (Category, Parent, Linkage, Tags, etc ...)
[switch]$Details,
# Indent nested topics and sections.
[switch]$Indent,
# Include a separator line between snippets.
[switch]$SeparateSnippets,
# Display Statblocks inline.
[switch]$InlineStats,
# Scale percentage for displaying Simple Pictures inline.
# Omitting this parameter, or setting it to 0
# will display thumbnails.
[Parameter()]
[int]$SimpleImageScale = 0,
# Scale percentage for displaying Smart Images inline.
# Omitting this parameter, or setting it to 0
# will display thumbnails.
[Parameter()]
[int]$SmartImageScale = 0,
# Preserve the text styles as defined in Realm Works.
[Parameter()]
[switch]$KeepStyles,
# Specify a different name for the CSS file.
# This does not create the CSS file. It only changes the name
# defined in the header of the HTML file.
[Parameter()]
[string]$CSSFileName = "main.css",
# Specify the path for an optional log file.
# [NOT WORKING YET]
[Parameter()]
[string]$Log
) # param
Function ParseTopic($PassedTopic,$Outputfile,$Sort,$Prefix,$Suffix,$Details,$Indent,$SeparateSnippets,$InlineStats,$SimpleImageScale,$SmartImageScale,$Parent,$TitleCSS,$TopicCSS,$TopicDetailsCSS,$SectionCSS,$SnippetCSS,$Indcrement,$KeepStyles,$Log) {
$TopicName = $PassedTopic.public_name
if ($Prefix -and $PassedTopic.Prefix) {$TopicName = $PassedTopic.Prefix + " - " + $TopicName}
if ($Suffix -and $PassedTopic.Suffix) {$TopicName = $TopicName + " (" + $PassedTopic.Suffix + ")"}
$ParentName = "Parent Topic: $Parent"
$CategoryName = "Category: " + $PassedTopic.category_name.Trim()
$TopicDetails = "$ParentName<br>$CategoryName"
If ($PassedTopic.tag_assign) {
$tagline = ParseTags $PassedTopic $Outputfile $Log
$TopicDetails = "$TopicDetails<br>$tagline"
} # If ($PassedTopic.tag_assign)
If ($PassedTopic.linkage) {
$linkage = ParseLinkage $PassedTopic $outputfile $Log
$TopicDetails = "$TopicDetails<br>$linkage"
} # If ($PassedTopic.linkage)
$TopicName = $TopicCSS.Replace("*",$TopicName)
$TopicDetails = $TopicDetailsCSS.Replace("*",$TopicDetails)
[System.IO.File]::AppendAllText($outputfile,$TopicName)
If ($Details) {[System.IO.File]::AppendAllText($outputfile,$TopicDetails)}
foreach ($Section in $PassedTopic.section) {
ParseSection $Section $Outputfile $SectionCSS $SnippetCSS $Indcrement $SeparateSnippets $InlineStats $SimpleImageScale $SmartImageScale $KeepStyles $Log
} # foreach ($Section in $PassedTopic.section)
Switch ($Sort) {
1 {$TopicList = $PassedTopic.topic | Sort-Object public_name}
2 {$TopicList = $PassedTopic.topic | Sort-Object prefix,public_name}
3 {$TopicList = $PassedTopic.topic | Sort-Object category_name,public_name}
4 {$TopicList = $PassedTopic.topic | Sort-Object category_name,prefix,public_name}
default {$TopicList = $PassedTopic.topic}
}
$Parent = $Parent + $PassedTopic.Public_Name + "/"
foreach ($Topic in $TopicList) {
If ($Indent) {
$SubTopicCSS = AddIndent $TopicCSS $Indcrement $Log
$SubTopicDetailsCSS = AddIndent $TopicDetailsCSS $Indcrement $Log
$SubSectionCSS = AddIndent $SectionCSS $Indcrement $Log
$SubSnippetCSS = AddIndent $SnippetCSS $Indcrement $Log
} else {
$SubTopicCSS = $TopicCSS
$SubTopicDetailsCSS = $TopicDetailsCSS
$SubSectionCSS = $SectionCSS
$SubSnippetCSS = $SnippetCSS
} # If ($Indent)
ParseTopic $Topic $Outputfile $Sort $Prefix $Suffix $Details $Indent $SeparateSnippets $InlineStats $SimpleImageScale $SmartImageScale $Parent $TitleCSS $SubTopicCSS $SubTopicDetailsCSS $SubSectionCSS $SubSnippetCSS $Indcrement $KeepStyles $Log
} # foreach ($Topic in $TopicList)
} # Function ParseTopic($PassedTopic)
Function ParseSection ($PassedSection,$Outputfile,$SectionCSS,$SnippetCSS,$Indcrement,$SeparateSnippets,$InlineStats,$SimpleImageScale,$SmartImageScale,$KeepStyles,$Log) {
$SectionName = $SectionCSS.Replace("*",$PassedSection.name)
[System.IO.File]::AppendAllText($outputfile,$sectionname)
# Add-Content -Path $outputfile -Value $SectionName
foreach ($Snippet in $PassedSection.snippet) {
ParseSnippet $Snippet $Outputfile $SnippetCSS $Indcrement $SeparateSnippets $InlineStats $SimpleImageScale $SmartImageScale $KeepStyles $Log
} # foreach ($Snippet in $PassedSection.snippet)
foreach ($Section in $PassedSection.section) {
If ($Indent) {
$SubSectionCSS = AddIndent $SectionCSS $Indcrement $Log
$SubSnippetCSS = AddIndent $SnippetCSS $Indcrement $Log
} else {
$SubSectionCSS = $SectionCSS
$SubSnippetCSS = $SnippetCSS
} # If ($Indent)
ParseSection $Section $Outputfile $SubSectionCSS $SubSnippetCSS $Indcrement $SeparateSnippets $InlineStats $SimpleImageScale $SmartImageScale $KeepStyles $Log
} # foreach ($Section in $PassedSection.section)
} # Function ParseSection ($PassedSection)
Function ParseSnippet ($PassedSnippet,$Outputfile,$SnippetCSS,$Indcrement,$SeparateSnippets,$InlineStats,$SimpleImageScale,$SmartImageScale,$KeepStyles,$Log) {
switch ($PassedSnippet.type) {
"Audio" {
$Type = "Audio File"
$Name = $PassedSnippet.ext_object.name
if (($name -eq $null) -or ($name -eq "") -or ($name -eq "&nbsp;")) {$name = "Unnamed"}
$Text = $Name + ": [$Type, no preview available]"
$annotation = $PassedSnippet.annotation
$annotation = ParseSnippetText $annotation $Log
if (($annotation -ne $null) -and ($annotation -ne "") -and ($annotation -ne "&nbsp;")) {
$Text = $Text + "<br>Annotation: $annotation"
} # if (($annotation -ne $null) -and ($annotation -ne ""))
$Text = $Text.Trim()
if ($SeparateSnippets) {$Text = $Text + "<hr>"}
$Text = $SnippetCSS.replace("*",$Text)
[System.IO.File]::AppendAllText($outputfile,$text)
# Add-Content -Path $outputfile -Value $Text
} # "Audio"
"Date_Game" {
$Text = $PassedSnippet.game_date.display
if (($PassedSnippet.Label -ne $null) -and ($PassedSnippet.Label -ne "") -and ($PassedSnippet.Label -ne "&nbsp;")) {
if ($PassedSnippet.Label.endswith(':')) {$LabelPrefix = $PassedSnippet.Label + ' '} else {$LabelPrefix = $PassedSnippet.Label + ': '}
$Text = $LabelPrefix + $Text
} # if ($PassedSnippet.Label -ne $null)
$annotation = $PassedSnippet.annotation
$annotation = ParseSnippetText $annotation $Log
if (($annotation -ne $null) -and ($annotation -ne "") -and ($annotation -ne "&nbsp;")) {
$Text = $Text + "<br>Annotation: $annotation"
} # if (($annotation -ne $null) -and ($annotation -ne ""))
if ($SeparateSnippets) {$Text = $Text + "<hr>"}
$Text = $SnippetCSS.Replace("*",$Text)
[System.IO.File]::AppendAllText($outputfile,$Text)
# Add-Content -Path $outputfile -Value $Text
} # Date_Game
"Date_Range" {
$Text = $PassedSnippet.date_range.display_start + " to " + $PassedSnippet.date_range.display_end
if (($PassedSnippet.Label -ne $null) -and ($PassedSnippet.Label -ne "") -and ($PassedSnippet.Label -ne "&nbsp;")) {
if ($PassedSnippet.Label.endswith(':')) {$LabelPrefix = $PassedSnippet.Label + ' '} else {$LabelPrefix = $PassedSnippet.Label + ': '}
$Text = $LabelPrefix + $Text
} # if ($PassedSnippet.Label -ne $null)
$annotation = $PassedSnippet.annotation
$annotation = ParseSnippetText $annotation $Log
if (($annotation -ne $null) -and ($annotation -ne "") -and ($annotation -ne "&nbsp;")) {
$Text = $Text + "<br>Annotation: $annotation"
}
if ($SeparateSnippets) {$Text = $Text + "<hr>"}
$Text = $SnippetCSS.Replace("*",$Text)
[System.IO.File]::AppendAllText($outputfile,$Text)
# Add-Content -Path $outputfile -Value $Text
} # Date_Range
"Foreign" {
$Type = "Foreign Object"
$Name = $PassedSnippet.ext_object.name
if (($name -eq $null) -or ($name -eq "") -or ($name -eq "&nbsp;")) {$name = "Unnamed"}
$Text = $Name + ": [$Type, no preview available]"
$annotation = $PassedSnippet.annotation
$annotation = ParseSnippetText $annotation $Log
if (($annotation -ne $null) -and ($annotation -ne "") -and ($annotation -ne "&nbsp;")) {
$Text = $Text + "<br>Annotation: $annotation"
} # if (($annotation -ne $null) -and ($annotation -ne ""))
$Text = $Text.Trim()
if ($SeparateSnippets) {$Text = $Text + "<hr>"}
$Text = $SnippetCSS.replace("*",$Text)
[System.IO.File]::AppendAllText($outputfile,$Text)
# Add-Content -Path $outputfile -Value $Text
} # "Foreign"
"HTML" {
$Type = "HTML Page (Complete)"
$Name = $PassedSnippet.ext_object.name
if (($name -eq $null) -or ($name -eq "") -or ($name -eq "&nbsp;")) {$name = "Unnamed"}
$Text = $Name + ": [$Type, no preview available]"
$annotation = $PassedSnippet.annotation
$annotation = ParseSnippetText $annotation $Log
if (($annotation -ne $null) -and ($annotation -ne "") -and ($annotation -ne "&nbsp;")) {
$Text = $Text + "<br>Annotation: $annotation"
} # if (($annotation -ne $null) -and ($annotation -ne ""))
$Text = $Text.Trim()
if ($SeparateSnippets) {$Text = $Text + "<hr>"}
$Text = $SnippetCSS.replace("*",$Text)
[System.IO.File]::AppendAllText($outputfile,$Text)
# Add-Content -Path $outputfile -Value $Text
} # "HTML"
"Labeled_Text" {
$Text = $PassedSnippet.contents
$TagPreface = '<span class="RWSnippet">'
if (($PassedSnippet.Label -ne $null) -and ($PassedSnippet.Label -ne "") -and ($PassedSnippet.Label -ne "&nbsp;")) {
if ($PassedSnippet.Label.endswith(':')) {$LabelPrefix = $PassedSnippet.Label + ' '} else {$LabelPrefix = $PassedSnippet.Label + ': '}
$InsertPoint = $Text.IndexOf($TagPreface) + $TagPreface.Length
$Text = $Text.insert($InsertPoint,$LabelPrefix)
} # if ($PassedSnippet.Label -ne $null)
$Text = InsertMargin $Text $SnippetCSS $Log
if ($SeparateSnippets) {$Text = $Text + "<hr>"}
$Text = $SnippetCSS.replace("*",$Text)
[System.IO.File]::AppendAllText($outputfile,$Text)
# Add-Content -Path $outputfile -Value $Text
} # "Labeled_Text"
"Multi_Line" {
if ($PassedSnippet.purpose -eq "directions_only") {
$Text = $PassedSnippet.gm_directions
$TagPreface = '<span class="RWSnippet">'
$LabelPrefix = 'GM Directions: '
$InsertPoint = $Text.IndexOf($TagPreface) + $TagPreface.Length
$Text = $Text.insert($InsertPoint,$LabelPrefix)
$Text = InsertMargin $Text $SnippetCSS $Log
If (-not $KeepStyles) {$Text = StripStyles $Text $Log}
if ($SeparateSnippets) {$Text = $Text + "<hr>"}
[System.IO.File]::AppendAllText($outputfile,$Text)
# Add-Content -Path $Outputfile -Value $Text
} elseif ($PassedSnippet.purpose -eq "Both") {
if ($PassedSnippet.gm_directions -ne $null) {
$Text = $PassedSnippet.gm_directions
$TagPreface = '<span class="RWSnippet">'
$LabelPrefix = 'GM Directions: '
$InsertPoint = $Text.IndexOf($TagPreface) + $TagPreface.Length
$Text = $Text.insert($InsertPoint,$LabelPrefix)
$Text = InsertMargin $Text $SnippetCSS $Log
If (-not $KeepStyles) {$Text = StripStyles $Text $Log}
if ($SeparateSnippets) {$Text = $Text + "<hr>"}
[System.IO.File]::AppendAllText($outputfile,$Text)
# Add-Content -Path $outputfile -Value $Text
} # if ($PassedSnippet.gm_directions -ne $null)
if ($PassedSnippet.contents -ne $null) {
$Text = InsertMargin $PassedSnippet.contents $SnippetCSS $Log
If (-not $KeepStyles) {$Text = StripStyles $Text $Log}
if ($SeparateSnippets) {$Text = $Text + "<hr>"}
[System.IO.File]::AppendAllText($outputfile,$Text)
# Add-Content -Path $outputfile -Value $Text
} # if ($PassedSnippet.contents -ne $null)
} elseif (($PassedSnippet.contents -ne $null) -and (($PassedSnippet.contents.contains("<ul")) -or ($PassedSnippet.contents.contains("<ol")) -or ($PassedSnippet.contents.contains("<table")))) {
$TagList = GetTagLocations $PassedSnippet.contents $Log
$Text = InsertFormattedMargins $PassedSnippet.contents $SnippetCSS $TagList $Log
If (-not $KeepStyles) {$Text = StripStyles $Text $Log}
if ($SeparateSnippets) {$Text = $Text + "<hr>"}
[System.IO.File]::AppendAllText($outputfile,$Text)
# Add-Content -Path $outputfile -Value $Text
} else {
$Text = InsertMargin $PassedSnippet.contents $SnippetCSS $Log
If (-not $KeepStyles) {$Text = StripStyles $Text $Log}
if ($SeparateSnippets) {$Text = $Text + "<hr>"}
[System.IO.File]::AppendAllText($outputfile,$Text)
# Add-Content -Path $outputfile -Value $Text
} # if ($PassedSnippet.purpose -eq "directions_only")
} # "Multi_Line"
"Numeric" {
$Text = $PassedSnippet.contents
if (($PassedSnippet.Label -ne $null) -and ($PassedSnippet.Label -ne "") -and ($PassedSnippet.Label -ne "&nbsp;")) {
if ($PassedSnippet.Label.endswith(':')) {$LabelPrefix = $PassedSnippet.Label + ' '} else {$LabelPrefix = $PassedSnippet.Label + ': '}
$Text = $LabelPrefix + $Text
} # if ($PassedSnippet.Label -ne $null)
$annotation = $PassedSnippet.annotation
$annotation = ParseSnippetText $annotation $Log
if (($annotation -ne $null) -and ($annotation -ne "") -and ($annotation -ne "&nbsp;")) {
$Text = $Text + "<br>Annotation: $annotation"
} # if (($annotation -ne $null) -and ($annotation -ne ""))
If (-not $KeepStyles) {$Text = StripStyles $Text $Log}
if ($SeparateSnippets) {$Text = $Text + "<hr>"}
$Text = $SnippetCSS.Replace("*",$Text)
[System.IO.File]::AppendAllText($outputfile,$Text)
# Add-Content -Path $outputfile -Value $Text
} # "Numeric"
"PDF" {
$Type = "PDF Document"
$Name = $PassedSnippet.ext_object.name
if (($name -eq $null) -or ($name -eq "") -or ($name -eq "&nbsp;")) {$name = "Unnamed"}
$Text = $Name + ": [$Type, no preview available]"
$annotation = $PassedSnippet.annotation
$annotation = ParseSnippetText $annotation $Log
if (($annotation -ne $null) -and ($annotation -ne "") -and ($annotation -ne "&nbsp;")) {
$Text = $Text + "<br>Annotation: $annotation"
} # if (($annotation -ne $null) -and ($annotation -ne ""))
$Text = $Text.Trim()
If (-not $KeepStyles) {$Text = StripStyles $Text $Log}
if ($SeparateSnippets) {$Text = $Text + "<hr>"}
$Text = $SnippetCSS.replace("*",$Text)
[System.IO.File]::AppendAllText($outputfile,$Text)
# Add-Content -Path $outputfile -Value $Text
} # "PDF"
"Picture" {
$FullImage = $PassedSnippet.ext_object.asset.contents
$ImageLink = '<a href="data:image/png;base64,' + $FullImage + '">Picture</a>'
$ImageName = $PassedSnippet.ext_object.name
if (($name -eq $null) -or ($name -eq "") -or ($name -eq "&nbsp;")) {$name = "Unnamed"}
$Text = $ImageName + ": [$ImageLink]"
$annotation = $PassedSnippet.annotation
$annotation = ParseSnippetText $annotation $Log
if (($annotation -ne $null) -and ($annotation -ne "") -and ($annotation -ne "&nbsp;")) {
$Text = $Text + "<br>Annotation: $annotation"
} # if (($annotation -ne $null) -and ($annotation -ne ""))
If (-not $KeepStyles) {$Text = StripStyles $Text $Log}
$Text = $SnippetCSS.replace("*",$Text)
[System.IO.File]::AppendAllText($outputfile,$Text)
# Add-Content -Path $Outputfile -Value $Text
If ($SimpleImageScale -eq 0) {
$Thumbnail = $PassedSnippet.ext_object.asset.thumbnail
$EncodedImage = '<img src="data:image/png;base64,' + $Thumbnail + '">'
} else {
$SimpleImageScale = $SimpleImageScale / 100
$SimpleImageScale = 'style="transform:scale(' + $SimpleImageScale + ');"'
$EncodedImage = '<img ' + $SimpleImageSCale + ' src="data:image/png;base64,' + $FullImage + '">'
}
$tag = "<img "
$EncodedImage = InsertMiscMargins $EncodedImage $SnippetCSS $tag $Log
if ($SeparateSnippets) {$EncodedImage = $EncodedImage + "<hr>"}
[System.IO.File]::AppendAllText($outputfile,$EncodedImage)
# Add-Content -Path $outputfile -Value $EncodedImage
} # "Picture"
"Portfolio" {
$Statblock = "Hero Lab Portfolio"
$Name = $PassedSnippet.ext_object.name
if (($name -eq $null) -or ($name -eq "") -or ($name -eq "&nbsp;")) {$name = "Unnamed"}
$Text = $Name + ": [$Statblock, no preview available]"
$annotation = $PassedSnippet.annotation
$annotation = ParseSnippetText $annotation $Log
if (($annotation -ne $null) -and ($annotation -ne "") -and ($annotation -ne "&nbsp;")) {
$Text = $Text + "<br>Annotation: $annotation"
} # if (($annotation -ne $null) -and ($annotation -ne ""))
$Text = $Text.Trim()
If (-not $KeepStyles) {$Text = StripStyles $Text $Log}
if ($SeparateSnippets) {$Text = $Text + "<hr>"}
$Stats = $SnippetCSS.replace("*",$Text)
[System.IO.File]::AppendAllText($outputfile,$Stats)
# Add-Content -Path $outputfile -Value $Stats
} # "Portfolio"
"Rich_Text" {
$Type = "Rich Text Document"
$Name = $PassedSnippet.ext_object.name
if (($name -eq $null) -or ($name -eq "") -or ($name -eq "&nbsp;")) {$name = "Unnamed"}
$Text = $Name + ": [$Type, no preview available]"
$annotation = $PassedSnippet.annotation
$annotation = ParseSnippetText $annotation $Log
if (($annotation -ne $null) -and ($annotation -ne "") -and ($annotation -ne "&nbsp;")) {
$Text = $Text + "<br>Annotation: $annotation"
} # if (($annotation -ne $null) -and ($annotation -ne ""))
$Text = $Text.Trim()
If (-not $KeepStyles) {$Text = StripStyles $Text $Log}
if ($SeparateSnippets) {$Text = $Text + "<hr>"}
$Text = $SnippetCSS.replace("*",$Text)
[System.IO.File]::AppendAllText($outputfile,$Text)
# Add-Content -Path $outputfile -Value $Text
} # "Rich Text"
"Smart_Image" {
$FullImage = $PassedSnippet.smart_image.asset.contents
$ImageLink = '<a href="data:image/png;base64,' + $FullImage + '">Smart Image</a>'
$ImageName = $PassedSnippet.smart_image.name
if (($ImageName -eq $null) -or ($ImageName -eq "") -or ($ImageName -eq "&nbsp;")) {$ImageName = "Unnamed"}
$Text = $ImageName + ": [$ImageLink]"
$annotation = $PassedSnippet.annotation
$annotation = ParseSnippetText $annotation $Log
if (($annotation -ne $null) -and ($annotation -ne "") -and ($annotation -ne "&nbsp;")) {
$Text = $Text + "<br>Annotation: $annotation"
} # if (($annotation -ne $null) -and ($annotation -ne ""))
If (-not $KeepStyles) {$Text = StripStyles $Text $Log}
$Text = $SnippetCSS.replace("*",$Text)
[System.IO.File]::AppendAllText($outputfile,$Text)
# Add-Content -Path $Outputfile -Value $Text
If ($SmartImageScale -eq 0) {
$Thumbnail = $PassedSnippet.smart_image.asset.thumbnail
$EncodedImage = '<img src="data:image/png;base64,' + $Thumbnail + '">'
} else {
$SmartImageScale = $SmartImageScale / 100
$SmartImageScale = 'style="transform:scale(' + $SmartImageScale + ');"'
$EncodedImage = '<img ' + $SmartImageSCale + ' src="data:image/png;base64,' + $FullImage + '">'
}
$tag = "<img "
$EncodedImage = InsertMiscMargins $EncodedImage $SnippetCSS $tag $Log
If ($SeparateSnippets) {$EncodedImage = $EncodedImage + "<hr>"}
[System.IO.File]::AppendAllText($outputfile,$EncodedImage)
# Add-Content -Path $outputfile -Value $EncodedImage
} # "Smart_Image"
"Statblock" {
$Statblock = "Stat Block"
$Name = $PassedSnippet.ext_object.name
if (($name -eq $null) -or ($name -eq "") -or ($name -eq "&nbsp;")) {$name = "Unnamed"}
$EncodedStats = $PassedSnippet.ext_object.asset.contents
$Stats = '<a href="data:text/html;base64,' + $EncodedStats + '">' + $Statblock + '</a>'
$Text = $Name + ": [$Stats]"
$annotation = $PassedSnippet.annotation
$annotation = ParseSnippetText $annotation $Log
if (($annotation -ne $null) -and ($annotation -ne "") -and ($annotation -ne "&nbsp;")) {
$Text = $Text + "<br>Annotation: $annotation"
} # if (($annotation -ne $null) -and ($annotation -ne ""))
$Text = $Text.Trim()
If ($SeparateSnippets) {$Text = $Text + "<hr>"}
$Stats = $SnippetCSS.replace("*",$Text)
[System.IO.File]::AppendAllText($outputfile,$Stats)
# Add-Content -Path $outputfile -Value $Stats
if ($InlineStats) {
$DecodedStats = [System.Text.Encoding]::ASCII.GetString([System.Convert]::FromBase64String($EncodedStats));
$PTag = $DecodedStats.IndexOf("<p ")
$BodyTag = $DecodedStats.IndexOf("</body>")
$SubStringStart = $PTag
$SubStringLength = $BodyTag - $PTag
$Body = $DecodedStats.substring($SubStringStart,$SubStringLength)
$Body = $Body.replace("RWLink","StatBlockLink")
$Body = $Body.replace("RWSnippet","StatBlockSnippet")
$Body = $Body.replace("RWDefault","StatBlockDefault")
$Body = $Body.replace("RWBullet","StatBlockBullet")
$Body = $Body.replace("RWEnumerated","StatBlockEnumerated")
$Body = $Body.replace(".td",".StatBlock-td")
$Body = $Body.replace(".tr","StatBlock-tr")
$Body = $Body.replace(".p","StatBlock-p")
If (-not $KeepStyles) {$Body = StripStyles $Body $Log}
if ($SeparateSnippets) {$Body = $Body + "<hr>"}
[System.IO.File]::AppendAllText($outputfile,$Body)
# Add-Content -Path $outputfile -Value $Body
} # if ($InlineStats)
} # "Statblock"
"Tag_Multi_Domain" {
$Text = ParseTags $PassedSnippet $Log
if (($PassedSnippet.Label -ne $null) -and ($PassedSnippet.Label -ne "") -and ($PassedSnippet.Label -ne "&nbsp;")) {
if ($PassedSnippet.Label.endswith(':')) {$LabelPrefix = $PassedSnippet.Label + ' '} else {$LabelPrefix = $PassedSnippet.Label + ': '}
$Text = $LabelPrefix + "<BR>$Text"
} # if ($PassedSnippet.Label -ne $null)
$annotation = $PassedSnippet.annotation
$annotation = ParseSnippetText $annotation $Log
if (($annotation -ne $null) -and ($annotation -ne "") -and ($annotation -ne "&nbsp;")) {
$Text = $Text + "<br>Annotation: $annotation"
} # if (($annotation -ne $null) -and ($annotation -ne ""))
If (-not $KeepStyles) {$Text = StripStyles $Text $Log}
$Text = $SnippetCSS.Replace("*",$Text)
if ($SeparateSnippets) {$Text = $Text + "<hr>"}
[System.IO.File]::AppendAllText($outputfile,$Text)
# Add-Content -Path $outputfile -Value $Text
} # "Tag_Multi_Domain"
"Tag_Standard" {
$Text = ParseTags $PassedSnippet $Log
if (($PassedSnippet.Label -ne $null) -and ($PassedSnippet.Label -ne "") -and ($PassedSnippet.Label -ne "&nbsp;")) {
if ($PassedSnippet.Label.endswith(':')) {$LabelPrefix = $PassedSnippet.Label + ' '} else {$LabelPrefix = $PassedSnippet.Label + ': '}
$Text = $LabelPrefix + "<BR>$Text"
} # if ($PassedSnippet.Label -ne $null)
$annotation = $PassedSnippet.annotation
$annotation = ParseSnippetText $annotation $Log
if (($annotation -ne $null) -and ($annotation -ne "") -and ($annotation -ne "&nbsp;")) {
$Text = $Text + "<br>Annotation: $annotation"
} # if (($annotation -ne $null) -and ($annotation -ne ""))
If (-not $KeepStyles) {$Text = StripStyles $Text $Log}
$Text = $SnippetCSS.Replace("*",$Text)
if ($SeparateSnippets) {$Text = $Text + "<hr>"}
[System.IO.File]::AppendAllText($outputfile,$Text)
# Add-Content -Path $outputfile -Value $Text
} # "Tag_Standard"
"Video" {
$Type = "Video File"
$Name = $PassedSnippet.ext_object.name
if (($name -eq $null) -or ($name -eq "") -or ($name -eq "&nbsp;")) {$name = "Unnamed"}
$Text = $Name + ": [$Type, no preview available]"
$annotation = $PassedSnippet.annotation
$annotation = ParseSnippetText $annotation $Log
if (($annotation -ne $null) -and ($annotation -ne "") -and ($annotation -ne "&nbsp;")) {
$Text = $Text + "<br>Annotation: $annotation"
} # if (($annotation -ne $null) -and ($annotation -ne ""))
$Text = $Text.Trim()
If (-not $KeepStyles) {$Text = StripStyles $Text $Log}
if ($SeparateSnippets) {$Text = $Text + "<hr>"}
$Text = $SnippetCSS.replace("*",$Text)
[System.IO.File]::AppendAllText($outputfile,$Text)
# Add-Content -Path $outputfile -Value $Text
} # "Video"
default {
# Do nothing here.
} # default
} # switch ($PassedSnippet.type)
} # Function ParseSnippet
Function ParseSnippetText ($PassedText,$Log) {
if ($PassedText -ne $null) {
$gt = $PassedText.Indexof('>')
} else {
$gt = -1
} # if ($PassedText -ne $null)
$Text = $null
While ($gt -ge 0) {
# $gt = $PassedText.Indexof(">",$RWSnippet)
$lt = $PassedText.Indexof("<",$gt)
$length = $lt-$gt
if ($length -gt 1) {$Text = $Text + $PassedText.substring($gt+1,$length-1)}
if ($lt -lt $gt) {
$gt = -1
} else {
$PassedText = $PassedText.substring($lt,$PassedText.length-$lt)
$gt = $PassedText.Indexof('>')
} # if ($lt -lt $gt)
} # While ($gt -ge 0)
# if ($Text.contains("&nbsp;")) {$Text = $Text.replace("&nbsp;","`r`n`r`n")}
Return $Text
} # Function ParseSnippetText
Function ParseTags ($PassedTags,$Log) {
# This block of code assumes that tags of the same domain will always be grouped together.
$domain = 0
$tagdomains = $PassedTags.tag_assign.domain_name
if ($tagdomains.count -gt 1) {
$tagdomain = $tagdomains[$domain]
} else {
$tagdomain = $tagdomains
}
$tagline = ""
foreach ($tag in $PassedTags.tag_assign) {
if ($tag.domain_name -eq $tagdomain) {
if ($tagline -eq "") {$tagline = $tagdomain + ": " + $tag.tag_name} else {$tagline = $tagline + ", " + $tag.tag_name}
$domain++
} else {
$tagdomain = $tag.domain_name
$tagline = $tagline + "<br>" + $tagdomain + ": " + $tag.tag_name
$domain++
} # if ($tag.domain_name -eq $tagdomain)
} # foreach ($tag in $PassedSnippet.tag_assign)
Return $tagline.trim()
} # Function ParseTags
Function ParseLinkage ($PassedTopic,$OutputFile,$Log) {
$Linkage = $PassedTopic.linkage
$LinkList = ""
foreach ($link in $linkage) {
if ($linklist -eq "") {$linklist = "Linkage: " + $link.target_name} else {$linklist = $linklist + ", " + $link.target_name}
} # foreach ($link in $linkage)
Return $Linklist
} # Function ParseLinkage
Function GetTagLocations ($PassedSnippet,$Log) {
$taglist = $null
# Get the locations of all the start tags.
$ul = $PassedSnippet.IndexOf("<ul")
$ol = $PassedSnippet.IndexOf("<ol")
$table = $PassedSnippet.IndexOf("<table")
While (($ul -ge 0) -or ($ol -ge 0) -or ($table -ge 0)) {
if ($ul -ge 0) {
$properties = @{
'Tag'='ul';
'Start'=$ul;
'End'=0
} # $properties
$TagLocation = New-Object –TypeName PSObject –Prop $properties
[array]$Taglist = $Taglist + $TagLocation
} # if ($ul -ge 0)
if ($ol -ge 0) {
$properties = @{
'Tag'='ol';
'Start'=$ol;
'End'=0
} # $properties
$TagLocation = New-Object –TypeName PSObject –Prop $properties
[array]$Taglist = $Taglist + $TagLocation
} # if ($ol -ge 0)
if ($table -ge 0) {
$properties = @{
'Tag'='table';
'Start'=$table;
'End'=0
} # $properties
$TagLocation = New-Object –TypeName PSObject –Prop $properties
[array]$Taglist = $Taglist + $TagLocation
} # if ($table -ge 0)
$Taglist = $Taglist | Sort-Object Start
$HighTag = $Taglist.Count-1
$StartPosition = $Taglist[$HighTag].Start + 1
$ul = $PassedSnippet.IndexOf("<ul",$StartPosition)
$ol = $PassedSnippet.IndexOf("<ol",$StartPosition)
$table = $PassedSnippet.IndexOf("<table",$StartPosition)
} # While (($ul -ge 0) -or ($ol -ge 0) -or ($table -ge 0))
# Get all the end tags.
foreach ($tag in $Taglist) {
$endtag = "</" + $tag.tag + ">"
$endtag = $PassedSnippet.IndexOf($endtag,$tag.Start + 1)
$Tag.end = $endtag + $endtag.length-1
} # foreach ($tag in $Taglist)
# Fill in the gaps, if there are any.
$firstitem = 0
$firstpos = 0
$lastitem = $Taglist.count -1
for ($item=$firstitem; $item -le $lastitem; $item++) {
if (($firstpos -lt $Taglist[$item].start)) {
$endpos = $Taglist[$item].start - 1
$properties = @{
'Tag'='text';
'Start'=$firstpos;
'End'=$endpos
} # $properties
$TagLocation = New-Object –TypeName PSObject –Prop $properties
[array]$gaplist = $gaplist + $TagLocation
} # if (($firstpos -lt $Taglist[$item].start))
if ($item -eq $lastitem) {
$firstpos = $Taglist[$item].end + 1
$endpos = $PassedSnippet.length - 1
$properties = @{
'Tag'='text';
'Start'=$firstpos;
'End'=$endpos
} # $properties
$TagLocation = New-Object –TypeName PSObject –Prop $properties
[array]$gaplist = $gaplist + $TagLocation
} # if ($item -eq $lastitem)
$firstpos = $taglist[$item].end+1
} # for ($item=$firstitem; $item -le $lastitem; $item++)
$Taglist = $Taglist + $gaplist
$Taglist = $Taglist | Sort-Object start
Return $Taglist
} # GetTagLocations
Function InsertFormattedMargins ($PassedSnippet,$CSSCode,$TagLocations,$Log) {
$FirstMargin = $CSSCode.IndexOf('s')
$LastMargin = $CSSCode.IndexOf('>')
$Length = $LastMargin-$FirstMargin
$MarginString = $CSSCode.substring($FirstMargin,$Length)
$MarginString = $MarginString + " "
$Text = ""
foreach ($tag in $TagLocations) {
$tagtext = $PassedSnippet.substring($tag.start,$tag.end-$tag.start+1)
Switch ($tag.tag) {
"text" {
$Text = $Text + $tagtext.replace('<p ',"<p $MarginString")
} # "text"
"ul" {
$Text = $Text + $tagtext.replace('<ul ',"<ul $MarginString")
} # "ul"
"ol" {
$Text = $Text + $tagtext.replace('<ol ',"<ol $MarginString")
} # "ol"
"table" {
$Text = $Text + $tagtext.replace('<table ',"<table $MarginString")
# $Text = $Text + $Text.replace('<p ',"<p $MarginString")
} # "table"
} # Switch ($tag.tag)
} # foreach ($tag in $TagLocations)
Return $Text
} # Function InsertFormattedMargins
Function InsertMiscMargins ($PassedSnippet,$CSSCode,$Tag,$Log) {
$FirstMargin = $CSSCode.IndexOf('s')
$LastMargin = $CSSCode.IndexOf('>')
$Length = $LastMargin-$FirstMargin
$MarginString = $CSSCode.substring($FirstMargin,$Length)
$MarginString = $MarginString + " "
$MarginString = $Tag + $MarginString
$Text = $PassedSnippet.replace($tag,$MarginString)
Return $Text
} # Function InsertMiscMargins
Function AddIndent ($CSSCode,$Indcrement,$Log) {
$FirstString = 'style="margin-left:'
$LastString = 'px;"'
$FirstIndex = $CSSCode.IndexOf($FirstString)
$LastIndex = $CSSCode.IndexOf($LastString,$FirstIndex)
$FirstMargin = $FirstIndex + $FirstString.Length
$Length = $LastIndex - $FirstMargin
$CurrentMargin = $CSSCode.substring($FirstMargin,$Length)
$NewMargin = $CurrentMargin.ToInt32($null) + $Indcrement
$NewMargin = $NewMargin.ToString()
$NewMargin = $FirstString + $NewMargin + $LastString
$LastIndex = $LastIndex + $LastString.Length
$Length = $LastIndex-$FirstIndex
$OldMargin = $CSSCode.substring($FirstIndex,$Length)
$NewCSS = $CSSCode.replace($OldMargin,$NewMargin)
Return $NewCSS
} # Function AddIndent
Function InsertMargin ($PassedSnippet,$CSSCode,$Log) {
$FirstMargin = $CSSCode.IndexOf('s')
$LastMargin = $CSSCode.IndexOf('>')
$Length = $LastMargin-$FirstMargin
$MarginString = $CSSCode.substring($FirstMargin,$Length)
$MarginString = $MarginString + " "
$PassedSnippet = $PassedSnippet.replace('<p ',"<p $MarginString")
Return $PassedSnippet
} # Function InsertMargin
Function StripStyles ($Text,$Log) {
$Standards = @('"font-family:',
';font-family:',
'"background-color:',
';background-color:',
'"background:',
';background:',
'"color:',
';color:'
'"font-size:',
';font-size:')
foreach ($Standard in $Standards) {
While ($Text.contains($Standard)) {
$SubStandard = $Standard.substring(1,$Standard.Length-1)
$Start = $Text.IndexOf($SubStandard)
$EndSemi = $Text.IndexOf(";",$Start)
$EndQuote = $Text.IndexOf('"',$Start)
If ($EndSemi -lt $EndQuote) {$End = $EndSemi} elseif ($EndQuote -lt $EndSemi) {$End = $EndQuote-1}
$Length = $End-$Start+1
if ($Length -ge 1) {
$Substring = $Text.Substring($Start,$End-$Start+1)
if (-not $Substring.contains("wingdIngs")) {$Text = $Text.Replace($Substring,"")}
} # if ($Length -ge 1)
} # While ($Text.contains($Standard))
} # foreach ($Standard in $Standards)
Return $Text
} # Function StripStyles
# Just leaving this bit here for later reference as I implement logging
# $ErrorActionPreference = 'Stop'
#
# Try {
#
# } Catch {
# $ErrorMessage = $_.Exception.Message
# $FailedItem = $_.Exception.ItemName
# ------------------------
# $e = $_.Exception
# $line = $_.InvocationInfo.ScriptLineNumber
# $msg = $e.Message
# } Finally {
#
# $Time=Get-Date
# "This script made a read attempt at $Time" | out-file c:\logs\ExpensesScript.log -append
# } # Try
Function ReportException ($CommandLine,$ErrorMsg,$ErrorObject) {
Write-Host "[ERROR]"
Write-Host
Write-Host " $CommandLine"
Write-Host
Write-Host " Error: $ErrorMsg"
Write-Host " Reason:" $ErrorObject.CategoryInfo.Category " - " $ErrorObject.ToString()
Write-Host " Location: Line" $ErrorObject.InvocationInfo.ScriptLineNumber ", Character" $ErrorObject.InvocationInfo.OffsetInLine
Write-Host " Line:" $ErrorObject.InvocationInfo.Line.Trim()
Write-Host "[/ERROR]"
# Write-Host
# Read-Host 'Press Enter to continue…' | Out-Null
Exit
} # Function FileException
# Main {
# Set all errors as terminating errors to facilitate error trapping.
$ErrorActionPreference = "Stop"
# Get Date and CommandLine for logging purposes.
$Date = Get-Date
$CommandLine = $PSCmdlet.MyInvocation.Line
# If the -Log option was invoked, log the current date and the full command line.
# If anything goes wrong with this, write the error to the console and exit.
if ($Log) {
Try {
$Date = $Date.ToString() + "`r`n"
$CommandLine = $CommandLine + "`r`n"
[System.IO.File]::WriteAllText($Log,$Date)
[System.IO.File]::AppendAllText($Log,$CommandLine)
} Catch {
$ErrorMsg = "Error: Cannot create log file."
ReportException $CommandLine $Error $_
Exit
} # Try
} # if ($Log)
# Setup CSS tags so all we have to do later is a string.replace of "*"
# with whatever text we wish to use. Also, the variable names will
# remind us which tags are for which elements.
$TitleCSS = "<h1>*</h1>"
$TopicCSS = '<h2 style="margin-left:5px;">*</h2>'
$TopicDetailsCSS = '<h3 style="margin-left:5px;">*</h3>'
$SectionCSS = '<h4 style="margin-left:5px;">*</h4>'
$SnippetCSS = '<p style="margin-left:5px;">*</p>'
$Indcrement = 50
# Make sure the value specified for -Sort is valid.
# If the value is invalid, write to the console and exit.
if (($Sort -lt 1) -or ($Sort -gt 4)) {
Write-Host "[ERROR]"
Write-Host " Invalid Sort value."
Write-Host
Write-Host " Valid options are:"
Write-Host " 1 = Sort by topic names"
Write-Host " 2 = Sort by topic prefixes first, then by topic names (this is the default value)"
Write-Host " 3 = Sort by topic category first, then by topic name"
Write-Host " 4 = Sort by topic category first, then by topic prefix, then by topic name"
Write-Host "[/ERROR]"
# Write-Host
# Read-Host 'Press Enter to continue…' | Out-Null
Exit
} # if (($Sort -lt 1) -or ($Sort -gt 4))
# Make sure the values specified for -SimpleImageScale and -SmartImageScale are valid.
# If either one is invalid, write to the console and exit.
if (($SimpleImageScale -lt 0) -or ($SimpleImageScale -gt 100) -or ($SmartImageScale -lt 0) -or ($SmartImageScale -gt 100)) {
Write-Host "[ERROR]"
Write-Host " SmartImageScale or SimpleImageScale out of range."
Write-Host
Write-Host " Value must be between 0 and 100."
Write-Host "[/ERROR]"
# Write-Host
# Read-Host 'Press Enter to continue…' | Out-Null
Exit
} # if (($Sort -lt 1) -or ($Sort -gt 4))
# Import data from the specified source file.
# If anything goes wrong with this, write the error to the console and exit.
Try {
[xml]$RWExportData = Get-Content -Path $Source
} Catch {
$ErrorMsg = "Error: Cannot read source file."
ReportException $CommandLine $Error $_
} # Try
# Get the title from the specified output file.
$Title = $RWExportData.Output.definition.details.name
# Create and prime the HTML output file.
# If anything goes wrong with this, write the error to the console and exit.
Try {
[System.IO.File]::WriteAllText($Destination,"<html>")
[System.IO.File]::AppendAllText($Destination,"<head>")
[System.IO.File]::AppendAllText($Destination,"<title>$Title</title>")
[System.IO.File]::AppendAllText($Destination,'<link rel="stylesheet" type="text/css" href="' + $CSSFilename + '">')
# Just in case this file gets posted on a public web site, tell googlebot not to index this page.
[System.IO.File]::AppendAllText($Destination,'<meta name="googlebot" content="noindex">')
# Continue priming the HTML output file.
[System.IO.File]::AppendAllText($Destination,"</head>")
[System.IO.File]::AppendAllText($Destination,"<body>")
[System.IO.File]::AppendAllText($Destination,$TitleCSS.Replace("*",$Title))
} Catch {
$ErrorMsg = "Error: Cannot write destination file."
ReportException $CommandLine $Error $_
} # Try
# Get the main content from the output file.
$Contents = $RWExportData.output.contents
# Get the topic list, and sort it according to the specified method.
Switch ($Sort) {
1 {$TopicList = $Contents.topic | Sort-Object public_name}
2 {$TopicList = $Contents.topic | Sort-Object prefix,public_name}
3 {$TopicList = $Contents.topic | Sort-Object category_name,public_name}
4 {$TopicList = $Contents.topic | Sort-Object category_name,prefix,public_name}
default {$TopicList = $Contents.topic}
} # Switch ($Sort)
$Parent = "/"
foreach ($Topic in $TopicList) {
ParseTopic $Topic $Destination $Sort $Prefix $Suffix $Details $Indent $SeparateSnippets $InlineStats $SimpleImageScale $SmartImageScale $Parent $TitleCSS $TopicCSS $TopicDetailsCSS $SectionCSS $SnippetCSS $Indcrement $KeepStyles $Log
} # foreach ($Topic in $Contents.topic)
# Close out the HTML file
[System.IO.File]::AppendAllText($Destination,"</body>")
[System.IO.File]::AppendAllText($Destination,"</html>")
# } Main
# https://blogs.technet.microsoft.com/heyscriptingguy/2011/07/24/create-a-simple-graphical-interface-for-a-powershell-script/
Function BuildCommandLine ($Script,$Source,$Destination,$Sort,$Simple,$Smart,$CSSFile,$Prefix,$Suffix,$Details,$Indent,$Inline,$Keep,$Separate,$Log,$LogName) {
$CommandLine = "$Script -Source '$Source' -Destination '$Destination' -Sort $Sort -SimpleImageScale $Simple -SmartImageScale $Smart -CSSFileName '$CSSFile'"
if ($Prefix) {$CommandLine = $CommandLine + " -Prefix"}
if ($Suffix) {$CommandLine = $CommandLine + " -Suffix"}
if ($Details) {$CommandLine = $CommandLine + " -Details"}
if ($Indent) {$CommandLine = $CommandLine + " -Indent"}
if ($Separate) {$CommandLine = $CommandLine + " -SeparateSnippets"}
if ($Inline) {$CommandLine = $CommandLine + " -InlineStats"}
if ($Keep) {$CommandLine = $CommandLine + " -KeepStyles"}
if ($Log) {$CommandLine = $CommandLine + " -Log '$LogName'"}
Return $CommandLine
} # Function BuildCommandLine
#Generated Form Function
function GenerateForm {
########################################################################
# Code Generated By: SAPIEN Technologies PrimalForms (Community Edition) v1.0.8.0
# Generated On: 7/3/2011 11:35 AM
# Generated By: sean.kearney
#
# Modified and adapted by EightBitz as a GUI for RWExport-To-HTML.ps1
# Modified and Adapted On: 1/24/2017 5:00 AM CST
########################################################################
#region Import the Assemblies
[reflection.assembly]::loadwithpartialname(“System.Windows.Forms”) | Out-Null
[reflection.assembly]::loadwithpartialname(“System.Drawing”) | Out-Null
#endregion
#region Generated Form Objects
$RWExportForm = New-Object System.Windows.Forms.Form
$ScriptButton = New-Object System.Windows.Forms.Button
$ScriptText = New-Object System.Windows.Forms.TextBox
$SourceButton = New-Object System.Windows.Forms.Button
$SourceText = New-Object System.Windows.Forms.TextBox
$DestinationButton = New-Object System.Windows.Forms.Button
$DestinationText = New-Object System.Windows.Forms.TextBox
$CSSButton = New-Object System.Windows.Forms.Button
$CSSText = New-Object System.Windows.Forms.TextBox
$LogCheck = New-Object System.Windows.Forms.CheckBox
$LogButton = New-Object System.Windows.Forms.Button
$LogText = New-Object System.Windows.Forms.TextBox
$SortLabel = New-Object System.Windows.Forms.Label
$SortComboBox = New-Object System.Windows.Forms.ComboBox
$SimpleImgLabel = New-Object System.Windows.Forms.Label
$SimpleImgText = New-Object System.Windows.Forms.TextBox
$SmartImgLabel = New-Object System.Windows.Forms.Label
$SmartImgText = New-Object System.Windows.Forms.TextBox
$PrefixCheck = New-Object System.Windows.Forms.CheckBox
$PrefixLabel = New-Object System.Windows.Forms.Label
$SuffixCheck = New-Object System.Windows.Forms.CheckBox
$SuffixLabel = New-Object System.Windows.Forms.Label
$DetailsCheck = New-Object System.Windows.Forms.CheckBox
$DetailsLabel = New-Object System.Windows.Forms.Label
$IndentCheck = New-Object System.Windows.Forms.CheckBox
$IndentLabel = New-Object System.Windows.Forms.Label
$InlineStatsCheck = New-Object System.Windows.Forms.CheckBox
$InlineStatsLabel = New-Object System.Windows.Forms.Label
$KeepStylesCheck = New-Object System.Windows.Forms.CheckBox
$KeepStylesLabel = New-Object System.Windows.Forms.Label
$SeparateCheck = New-Object System.Windows.Forms.CheckBox
$SeparateLabel = New-Object System.Windows.Forms.Label
$CommandLabel = New-Object System.Windows.Forms.Label
$CommandText = New-Object System.Windows.Forms.TextBox
$RunButton = New-Object System.Windows.Forms.Button
$SaveButton = New-Object System.Windows.Forms.Button
$LoadButton = New-Object System.Windows.Forms.Button
$InitialFormWindowState = New-Object System.Windows.Forms.FormWindowState
#endregion Generated Form Objects
#———————————————-
#Generated Event Script Blocks
#———————————————-
#Provide Custom Code for events specified in PrimalForms.
$handler_ScriptButton_Click={
$OpenFileDialog = New-Object System.Windows.Forms.OpenFileDialog
$OpenFileDialog.initialDirectory = ".\"
$OpenFileDialog.filter = “PowerShell Scripts (*.ps1)| *.ps1”
# $OpenFileDialog.showhelp = $true
[void]$OpenFileDialog.ShowDialog()
$ScriptText.Text = $OpenFileDialog.filename.ToString()
$SortMethod = $SortComboBox.SelectedIndex + 1
$CommandLine = BuildCommandLine $ScriptText.Text $SourceText.Text $DestinationText.Text $SortMethod $SimpleImgText.Text $SmartImgText.Text $CSSText.Text $PrefixCheck.Checked $SuffixCheck.Checked $DetailsCheck.checked $IndentCheck.Checked $InlineStatsCheck.Checked $KeepStylesCheck.Checked $SeparateCheck.Checked $LogCheck.Checked $LogText.Text
$CommandText.Text = $CommandLine
} # $handler_ScriptButton_Click
$handler_TextBox_LostFocus={
$SortMethod = $SortComboBox.SelectedIndex + 1
$CommandLine = BuildCommandLine $ScriptText.Text $SourceText.Text $DestinationText.Text $SortMethod $SimpleImgText.Text $SmartImgText.Text $CSSText.Text $PrefixCheck.Checked $SuffixCheck.Checked $DetailsCheck.checked $IndentCheck.Checked $InlineStatsCheck.Checked $KeepStylesCheck.Checked $SeparateCheck.Checked $LogCheck.Checked $LogText.Text
$CommandText.Text = $CommandLine
} # $handler_ScriptText_LostFocus
$handler_SourceButton_Click={
$OpenFileDialog = New-Object System.Windows.Forms.OpenFileDialog
$OpenFileDialog.initialDirectory = ".\"
$OpenFileDialog.filter = “Realm Works Exports (*.RWOutput)| *.RWOutput”
# $OpenFileDialog.showhelp = $true
[void]$OpenFileDialog.ShowDialog()
$SourceText.Text = $OpenFileDialog.filename.ToString()
$SortMethod = $SortComboBox.SelectedIndex + 1
$CommandLine = BuildCommandLine $ScriptText.Text $SourceText.Text $DestinationText.Text $SortMethod $SimpleImgText.Text $SmartImgText.Text $CSSText.Text $PrefixCheck.Checked $SuffixCheck.Checked $DetailsCheck.checked $IndentCheck.Checked $InlineStatsCheck.Checked $KeepStylesCheck.Checked $SeparateCheck.Checked $LogCheck.Checked $LogText.Text
$CommandText.Text = $CommandLine
} # $handler_SourceButton_Click
$handler_DestinationButton_Click={
$SaveFileDialog = New-Object System.Windows.Forms.SaveFileDialog
$SaveFileDialog.initialDirectory = ".\"
$SaveFileDialog.filter = “HTML Files (*.html)| *.html”
# $OpenFileDialog.showhelp = $true
[void]$SaveFileDialog.ShowDialog()
$DestinationText.Text = $SaveFileDialog.filename
$SortMethod = $SortComboBox.SelectedIndex + 1
$CommandLine = BuildCommandLine $ScriptText.Text $SourceText.Text $DestinationText.Text $SortMethod $SimpleImgText.Text $SmartImgText.Text $CSSText.Text $PrefixCheck.Checked $SuffixCheck.Checked $DetailsCheck.checked $IndentCheck.Checked $InlineStatsCheck.Checked $KeepStylesCheck.Checked $SeparateCheck.Checked $LogCheck.Checked $LogText.Text
$CommandText.Text = $CommandLine
} # $handler_DestinationButton_Click
$handler_CSSButton_Click={
$SaveFileDialog = New-Object System.Windows.Forms.SaveFileDialog
$SaveFileDialog.initialDirectory = ".\"
$SaveFileDialog.filter = “CSS Files (*.css)| *.css”
# $OpenFileDialog.showhelp = $true
[void]$SaveFileDialog.ShowDialog()
$CSSText.Text = $SaveFileDialog.filename
$SortMethod = $SortComboBox.SelectedIndex + 1
$CommandLine = BuildCommandLine $ScriptText.Text $SourceText.Text $DestinationText.Text $SortMethod $SimpleImgText.Text $SmartImgText.Text $CSSText.Text $PrefixCheck.Checked $SuffixCheck.Checked $DetailsCheck.checked $IndentCheck.Checked $InlineStatsCheck.Checked $KeepStylesCheck.Checked $SeparateCheck.Checked $LogCheck.Checked $LogText.Text
$CommandText.Text = $CommandLine
} # $handler_CSSButton_Click
$handler_CSSText_LostFocus={
$SortMethod = $SortComboBox.SelectedIndex + 1
$CommandLine = BuildCommandLine $ScriptText.Text $SourceText.Text $DestinationText.Text $SortMethod $SimpleImgText.Text $SmartImgText.Text $CSSText.Text $PrefixCheck.Checked $SuffixCheck.Checked $DetailsCheck.checked $IndentCheck.Checked $InlineStatsCheck.Checked $KeepStylesCheck.Checked $SeparateCheck.Checked $LogCheck.Checked $LogText.Text
$CommandText.Text = $CommandLine
} # $handler_CSSText_LostFocus
$handler_LogButton_Click={
$OpenFileDialog = New-Object System.Windows.Forms.OpenFileDialog
$OpenFileDialog.initialDirectory = ".\"
$OpenFileDialog.filter = “All files (*.*)| *.*
# $OpenFileDialog.showhelp = $true
[void]$OpenFileDialog.ShowDialog()
$LogText.Text = $OpenFileDialog.filename.ToString()
$SortMethod = $SortComboBox.SelectedIndex + 1
$CommandLine = BuildCommandLine $ScriptText.Text $SourceText.Text $DestinationText.Text $SortMethod $SimpleImgText.Text $SmartImgText.Text $CSSText.Text $PrefixCheck.Checked $SuffixCheck.Checked $DetailsCheck.checked $IndentCheck.Checked $InlineStatsCheck.Checked $KeepStylesCheck.Checked $SeparateCheck.Checked $LogCheck.Checked $LogText.Text
$CommandText.Text = $CommandLine
} # $handler_LogButton_Click
$SortComboBox_SelectedIndexChanged={
$SortMethod = $SortComboBox.SelectedIndex + 1
$CommandLine = BuildCommandLine $ScriptText.Text $SourceText.Text $DestinationText.Text $SortMethod $SimpleImgText.Text $SmartImgText.Text $CSSText.Text $PrefixCheck.Checked $SuffixCheck.Checked $DetailsCheck.checked $IndentCheck.Checked $InlineStatsCheck.Checked $KeepStylesCheck.Checked $SeparateCheck.Checked $LogCheck.Checked $LogText.Text
$CommandText.Text = $CommandLine
} # $SortComboBox_SelectedIndexChanged
$handler_CheckBox_CheckStateChanged={
$SortMethod = $SortComboBox.SelectedIndex + 1
$CommandLine = BuildCommandLine $ScriptText.Text $SourceText.Text $DestinationText.Text $SortMethod $SimpleImgText.Text $SmartImgText.Text $CSSText.Text $PrefixCheck.Checked $SuffixCheck.Checked $DetailsCheck.checked $IndentCheck.Checked $InlineStatsCheck.Checked $KeepStylesCheck.Checked $SeparateCheck.Checked $LogCheck.Checked $LogText.Text
$CommandText.Text = $CommandLine
} # $handler_CheckBox_CheckStateChanged
$handler_LogCheck_CheckStateChanged={
if ($LogCheck.Checked) {
$LogButton.Enabled = $true
$LogText.Enabled = $true
} else {
$LogButton.Enabled = $false
$LogText.Enabled = $false
} # if ($LogCheck.Checked)
$SortMethod = $SortComboBox.SelectedIndex + 1
$CommandLine = BuildCommandLine $ScriptText.Text $SourceText.Text $DestinationText.Text $SortMethod $SimpleImgText.Text $SmartImgText.Text $CSSText.Text $PrefixCheck.Checked $SuffixCheck.Checked $DetailsCheck.checked $IndentCheck.Checked $InlineStatsCheck.Checked $KeepStylesCheck.Checked $SeparateCheck.Checked $LogCheck.Checked $LogText.Text
$CommandText.Text = $CommandLine
} # $handler_LogCheck_CheckStateChanged
$handler_RWEXportForm_Shown={
$SortMethod = $SortComboBox.SelectedIndex + 1
$CommandLine = BuildCommandLine $ScriptText.Text $SourceText.Text $DestinationText.Text $SortMethod $SimpleImgText.Text $SmartImgText.Text $CSSText.Text $PrefixCheck.Checked $SuffixCheck.Checked $DetailsCheck.checked $IndentCheck.Checked $InlineStatsCheck.Checked $KeepStylesCheck.Checked $SeparateCheck.Checked $LogCheck.Checked $LogText.Text
$CommandText.Text = $CommandLine
}
$handler_RunButton_Click={
$RWExportForm.Enabled = $false
Invoke-Expression $CommandText.Text
$RWExportForm.Enabled = $true
} # $handler_RunButton_Click
$handler_SaveButton_Click={
$SaveFileDialog = New-Object System.Windows.Forms.SaveFileDialog
$SaveFileDialog.initialDirectory = ".\"
$SaveFileDialog.filter = “PowerShell Files (*.ps1)| *.ps1”
# $OpenFileDialog.showhelp = $true
[void]$SaveFileDialog.ShowDialog()
$CommandText.Text | Out-File $SaveFileDialog.filename
} # $handler_SaveButton_Click
$handler_LoadButton_Click={
} # $handler_LoadButton_Click
$OnLoadForm_StateCorrection={
#Correct the initial state of the form to prevent the .Net maximized form issue
$RWExportForm.WindowState = $InitialFormWindowState
} # $OnLoadForm_StateCorrection
#———————————————-
#region Generated Form Code
$RWExportForm.Text = “RWExport-To-HTML”
$RWExportForm.Name = “RWExport-To-HTML”
$RWExportForm.DataBindings.DefaultDataSourceUpdateMode = 0
$System_Drawing_Size = New-Object System.Drawing.Size
$System_Drawing_Size.Width = 650
$System_Drawing_Size.Height = 450
$RWExportForm.ClientSize = $System_Drawing_Size
$RWExportForm.Add_Shown($handler_RWEXportForm_Shown)
$x = 15
$y = 15
$xpadding = 10
$ypadding = 5
$Tab = 0
$ScriptButton.TabIndex = $Tab
$relativex = $x
$relativey = $y
$ScriptButton.Location = New-Object System.Drawing.Size($relativex,$relativey)
$ScriptButton.Name = “ScriptButton”
$Width = 100
$Height = 25
$ScriptButton.Size = New-Object System.Drawing.Size($Width,$Height)
$ScriptButton.Text = “Script File”
$ScriptButton.add_Click($handler_ScriptButton_Click)
$Tab = $Tab + 1
$ScriptText.TabIndex = $Tab
$relativex = $relativex + $Width + $xpadding
$relativey = $relativey
$ScriptText.Location = New-Object System.Drawing.Size($relativex,$relativey)
$ScriptText.Name = “ScriptText”
$Width = 510
$Height = 25
$ScriptText.Size = New-Object System.Drawing.Size($Width,$Height)
$ScriptText.Text = “.\RWExport-To-HTML.ps1”
$ScriptText.add_LostFocus($handler_TextBox_LostFocus)
$Tab = $Tab + 1
$SourceButton.TabIndex = $Tab
$relativex = $x
$relativey = $relativey + $height + $ypadding
$SourceButton.Location = New-Object System.Drawing.Size($relativex,$relativey)
$SourceButton.Name = “SourceButton”
$Width = 100
$Height = 25
$SourceButton.Size = New-Object System.Drawing.Size($Width,$Height)
$SourceButton.Text = “Source File”
$SourceButton.add_Click($handler_SourceButton_Click)
$Tab = $Tab + 1
$SourceText.TabIndex = $Tab
$relativex = $relativex + $Width + $xpadding
$relativey = $relativey
$SourceText.Location = New-Object System.Drawing.Size($relativex,$relativey)
$SourceText.Name = “SourceText”
$Width = 510
$Height = 25
$SourceText.Size = New-Object System.Drawing.Size($Width,$Height)
$SourceText.Text = “.\MyRealm.rwoutput”
$SourceText.add_LostFocus($handler_TextBox_LostFocus)
$Tab = $Tab + 1
$DestinationButton.TabIndex = $Tab
$relativex = $x
$relativey = $relativey + $height + $ypadding
$DestinationButton.Location = New-Object System.Drawing.Size($relativex,$relativey)
$DestinationButton.Name = “DestinationButton”
$Width = 100
$Height = 25
$DestinationButton.Size = New-Object System.Drawing.Size($Width,$Height)
$DestinationButton.Text = “Destination File”
$DestinationButton.add_Click($handler_DestinationButton_Click)
$Tab = $Tab + 1
$DestinationText.TabIndex = $Tab
$relativex = $relativex + $Width + $xpadding
$relativey = $relativey
$DestinationText.Location = New-Object System.Drawing.Size($relativex,$relativey)
$DestinationText.Name = “DestinationText”
$Width = 510
$Height = 25
$DestinationText.Size = New-Object System.Drawing.Size($Width,$Height)
$DestinationText.Text = “.\MyRealm.html”
$DestinationText.add_LostFocus($handler_TextBox_LostFocus)
$Tab = $Tab + 1
$CSSButton.TabIndex = $Tab
$relativex = $x
$relativey = $relativey + $height + $ypadding
$CSSButton.Location = New-Object System.Drawing.Size($relativex,$relativey)
$CSSButton.Name = “CSSButton”
$Width = 100
$Height = 25
$CSSButton.Size = New-Object System.Drawing.Size($Width,$Height)
$CSSButton.Text = “CSS File”
$CSSButton.add_Click($handler_CSSButton_Click)
$Tab = $Tab + 1
$CSSText.TabIndex = $Tab
$relativex = $relativex + $Width + $xpadding
$relativey = $relativey
$CSSText.Location = New-Object System.Drawing.Size($relativex,$relativey)
$CSSText.Name = “CSSText”
$Width = 510
$Height = 25
$CSSText.Size = New-Object System.Drawing.Size($Width,$Height)
$CSSText.Text = “main.css”
$CSSText.add_LostFocus($handler_TextBox_LostFocus)
$Tab = $Tab + 1
$LogCheck.TabIndex = $Tab
$relativex = $x
$relativey = $relativey + $height + $ypadding
$LogCheck.Location = New-Object System.Drawing.Size($relativex,$relativey)
$LogCheck.Name = “LogCheck”
$Width = 15
$Height = 25
$LogCheck.Size = New-Object System.Drawing.Size($Width,$Height)
$LogCheck.Checked = $false
$LogCheck.Add_CheckStateChanged($handler_LogCheck_CheckStateChanged)
$Tab = $Tab + 1
$LogButton.TabIndex = $Tab
$relativex = $relativex + $Width + $xpadding
$relativey = $relativey
$LogButton.Location = New-Object System.Drawing.Size($relativex,$relativey)
$LogButton.Name = “LogButton”
$Width = 75
$Height = 25
$LogButton.Size = New-Object System.Drawing.Size($Width,$Height)
$LogButton.Text = “Log File”
$LogButton.add_Click($handler_LogButton_Click)
$LogButton.Enabled = $false
$Tab = $Tab + 1
$LogText.TabIndex = $Tab
$relativex = $relativex + $Width + $xpadding
$relativey = $relativey
$LogText.Location = New-Object System.Drawing.Size($relativex,$relativey)
$LogText.Name = “LogText”