[Parameter(Mandatory, ValueFromPipeline, ValueFromPipelineByPropertyName )] [ValidateScript({ if ($_ -like “*/*”) { # if the specified IP format is — 10.10.10.0/24 $temp = $_ -split ‘/’ If (([ValidateRange(0,32)][int]$subnetmask = $temp[1]) -and ([bool]($temp[0] -as [ipaddress]))) { Return $true } } else {# if the specified IP format is — 10.10.10.0 (along with this argument to Mask parameter is also provided) if ( [bool]($_ -as [ipaddress])) { return $true } else { throw “IP validation failed” } } })] [Alias(“IPAddress”,”NetworkRange”)] [string]$IP,
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
|
[fusion_builder_container hundred_percent=“yes” overflow=“visible”][fusion_builder_row][fusion_builder_column type=“1_1” background_position=“left top” background_color=“” border_size=“” border_color=“” border_style=“solid” spacing=“yes” background_image=“” background_repeat=“no-repeat” padding=“” margin_top=“0px” margin_bottom=“0px” class=“” id=“” animation_type=“” animation_speed=“0.3” animation_direction=“left” hide_on_mobile=“no” center_content=“no” min_height=“none”][Parameter(Mandatory,
ValueFromPipeline,
ValueFromPipelineByPropertyName
)]
[ValidateScript({
if ($_ -like “*/*”)
{ # if the specified IP format is — 10.10.10.0/24
$temp = $_ -split ‘/’
If (([ValidateRange(0,32)][int]$subnetmask = $temp[1]) -and ([bool]($temp[0] -as [ipaddress])))
{
Return $true
}
}
else
{# if the specified IP format is — 10.10.10.0 (along with this argument to Mask parameter is also provided)
if ( [bool]($_ -as [ipaddress]))
{
return $true
}
else
{
throw “IP validation failed”
}
}
})]
[Alias(“IPAddress”,“NetworkRange”)]
[string]$IP,
|
They used a lot of access to dotnet class, such as this call to system.net.dns to resolve the machines hostname.
|
$hostname = ([System.Net.Dns]::GetHostEntry(“$IPAddress”)).HostName
|
2) Gater server information:
What was asked here, was to retrieve a lot of information from the different servers / IP’s that would have been identified in section 1. This is pretty much a routine task if you have participated to the scripting games before 😉
Of course, this information can be retrieved very easily with WMI. François-Wavier (The lazy Win admin) and Guido wrote that part of the script and did great good job! They gave for example the possibilty to choose an alternante protocol :
|
[Parameter(
Mandatory,
HelpMessage=“Specify the protocol to use”)]
[ValidateSet(“WSMAN”,“DCOM”)]
[String]$Protocol = ‘WSMAN’,
|
They also did some very strong parameter validation and offered directly the possiblity to run the script with alternante credentials by integrating the following code:
|
[Alias(“RunAs”)]
[System.Management.Automation.Credential()]
$Credential = [System.Management.Automation.PSCredential]::Empty,
|
also every set of data was possible to get retrieved individually from each other by calling each parameter with “switch”
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
|
[Parameter(
ParameterSetName=“AllInformation”)]
[Switch]$AllInformation,
[Parameter(
ParameterSetName=“Information”)]
[Switch]$HardwareInformation,
[Parameter(
ParameterSetName=“Information”)]
[Switch]$LastPatchInstalled,
[Parameter(
ParameterSetName=“Information”)]
[Switch]$LastReboot,
[Parameter(
ParameterSetName=“Information”)]
[Switch]$ApplicationsInstalled,
[Parameter(
ParameterSetName=“Information”)]
[Switch]$WindowsComponents
|
|
And with these different parameters, the command “Get-WmiObject” would be called with a method called : <del>“Splitting”</del>. Splatting (Thanks for the correction FX ;) )
This technic was totally new for me! And thus the the first thing I learned during these scripting games :D).It avoids you to retype over and over again a set of variables that you would call for specefic parameters. (In our case it was errorAction errorVariable and Computername).
You basically create a hash table that you call later respecting this syntax :
|
|
Your-Command @hastablename
|
|
An example from our script would make it clearer I guess :
|
|
# Define Splatting
$CIMSessionParams = @{
ComputerName = $Computer
ErrorAction = ‘Stop’
ErrorVariable = ‘ProcessErrorCIM’
}
|
|
Creating of the hash table with main variables for each parameter.
The Hastable will ten be simply used like this :
|
|
$CimSession = New-CimSession @CIMSessionParams
|
Now lets look into the export part.
3) Exporting the data:
a)The graphics
We basically divided the export part into two sub parts : Generating the graphic, and exporting the data + the graphic.
Benjamin did a great job on generating beautifull exports like the one below with the function he build :
Chart export example
I have been focusing on the export parts. The HTML part was pretty simple, especially since we used the “-fragment” parameter of the “ConvertTo-HTML.
Actually, it became very easy once I read this super article from the “powerShell Deep Dives” book. There was an article about html export and it seemed to be tailored for us! (I must say, that in general, this book is really good !)
The article has been written by “Jonathan Medd” , he is part of one of the Scripting games “coaches” and you can visit his blog here.
The article basically indicated how to use the -fragment parameter of the “ExportTo-Html” cmdlet and how to add an image into the export ; Perfect ! That’s exactly what we needed !
Benny has a lot of experience in generating these kind of reports, and came with the idea to use a function that would actually transform the graph into “bytes” version, and intégrated directly in te script. This means that the image file of te chart actually never needs to be saved on the file system. That’s great !
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
|
Function Get-Base64Image {
[cmdletbinding()]
Param(
[Parameter(mandatory=$true)]$Path = $(throw “Path is mandatory, please provide a value.”)
)
begin{}
process{
$ImageBytes = [Convert]::ToBase64String((Get-Content $Path -Encoding Byte))
}
End{
return $ImageBytes
}
}
|
This is what we came up with.
At the end, the HTML export section looked like this:
|
ExportTo-html -Image $ByteImage -Data $data -Path $ExportPath -title $Title -Subtitle $SubTitle
|
($ExportPath would of course contain the date and time of when the file was generated followed by the .html extension).
And this is what the HTML export looked like after Benny re-aranged the CSS with his crazy “gandalfy” CSS little fingers 😉
And the data section here :
It looks good doesn’t it ? 😉
b) The other exports sections: CSV and Powerpoint.
The scenario asked for HTML, CSV, and PowerPoint exports. HTML we got it covered up here, and CSV, was actually the first one I wrote since it was so simple to that with the integrated cmdlet in powershell
|
$Data | Export-Csv -Path $ExportPath -NoTypeInformation
|
But exporting to PowerPoint ?!! I have written in the past a script that would generate automatically the documentation for a script by reading its comment based help section and exporting it to a predefined word template.(Maybe I should think of blogging about that scriptone day…) I used com objects for that.
So, I knew I was looking for Powerpoint exports with COM objects.
And here, i stumbled in a few problems:
- The first one was concerning the fact that I couldn’t find anything like asked in the scenario that could fullfill our needs.
- The second one, is that either the documentation of the COM objects are not so well written (FYI: English is also not my mother language), or COM objects is simply just not that easy to understand.
I would say both !!
Anyways, I managed to swim through this event, and learned a LOT on that topic. I will not post any code concerning the PowerPoint export part since I am planning to blog about it soon.
Ineed, the lack of infos available on the internet (or at least my searching results where not concluding at all!) gave me the idea to write something that could explain a bit how theses COM objects work.
In the mean time, find here what our powerpoint export looked like 😉
It is pretty basic I agree. (I am not really an artist as you can see ;)) But this is generated automatically, and ready to be used for a presentation 🙂
III) The biggest learning point : Putting everyting together.
Dividing a script in 6 parts, let them all be written by 6 different (amazing !) scripters, and then put everything together in one and unique script is something, that none of us had done before.
I have worked on projects where several scripters would each of them write a script that would do certain actions to a system (in my case SCCM, Active Directory, CSV files). But our scripts were dependant on the results that the scripts would have on the system.(EG: Computer object in OU, Collection present in SCCM etc..) But not on each other function or script.
Here, it was a hole new experience since we wanted to have 1 script, that could be called very easil, with only a few arguments. I personally think that it would not have been that of a problem if this task was done alone. But here we had to face different scripters, different time zones (4!!) different scripting styles.
We tried to organise, before even starting scripting, the functions that needed to be written, and what kind of export they needed to have as input & output. But, even with that, it wasn’t so easy.
So putting the wole script together didn’t worked out as expect. We deceided to upload the three different sections as seperate scripts. After all, the scenario mentionned the fact that everything should be set all into the same script 😉
Anyways, I really think that working as a team for the winter scripting games is a great idea in condition that there is enough work to share between 6 team members of course ! 😉
Well, that’s it for this review. Now, it is time to Attack the second (the first ?) event : “Pairs” written by “the” PowerShell legend himself : “Ed Wilson” 🙂
Have fun ! Proost !
Leave A Comment