How to optimize multiple if statements in Powershell? - powershell

This is my code :
Function CleanUpOracle
{
if ($Requete)
{
$Requete.Dispose()
}
if ($ExecuteRequete)
{
$ExecuteRequete.Dispose()
}
if ($Transaction)
{
$Transaction.Dispose()
}
if ($OracleConnexion)
{
$OracleConnexion.close()
$OracleConnexion.Dispose()
}
if ($Log.id)
{
$Log.PSObject.Properties.Remove('id')
}
}
I'm testing if a variable exist then {do something}
But in the future I'll many variable to test, I don't want to have hundred lines with that.
How can I optimize this? Maybe with a switch but how?
Thanks !

If you want to conditionally call Dispose against multiple items you can stream them from a list into the ForEach-Object (whose alias is %):
#($Requete, $ExecuteRequete, $Transaction, $OracleConnexion) |
% {if($_) {$_.Dispose()} }
NOTE: I've split this onto multiple lines for readability.

Related

Duck typing for indexed iteratables in Powershell

Instead of piping over collections, it's sometimes more convenient to procedurally loop through them. And to avoid differentiating between $_ and $_.Key/$_.Value depending on input, a more consistent key/value handling would be nice:
ForEach-KV $object { Param($k, $v); do-stuff }
However a common type probing has its drawbacks:
#-- iterate over dicts/objects/arrays using scriptblock with Param($k,$v)
function ForEach-KV {
Param($var, $cb, $i=0)
switch ($var.GetType().Name) {
Array { $var | % { $cb.Invoke($i++, $_) } }
HashTable { $var.Keys | % { $cb.Invoke($_, $var[$_]) } }
"Dictionary``2" { $var.Keys | % { $cb.Invoke($_, $var.Item($_)) } }
PSobject { $var.GetIterator() | % { $cb.Invoke($_.Key, $_.Value) } }
PSCustomObject { $var.GetIterator() | % { $cb.Invoke($_.Key, $_.Value) } }
default { $cb.Invoke($i++, $_) }
}
}
Apart from that one irritating type name, there's a bit much duplication here. Which is why I was looking around for duck typing in Powershell.
For hashes and objects, it's easiest/obvious to probe for .getIterator or .getEnumerator (never couldn't quite remember which belongs to which anyway):
switch ($_) {
{ $_.GetEnumerator } { do-loopy }
{ $_.GetIterator } { do-otherloopy }
But now I'm not quite sure what to do about arrays here. There's not that one behaviour indicator in [array]s methods that really sticks out.
.Get() does seem unique (at least not a method in HashTables or PSObjects), but sounds a bit too generic even for type guessing
.Add() might as well be an integer method(?)
.GetUpperBound() etc. come off as a bit too specific already.
So, is there a standard method that says "arrayish", preferrably something that's shared among other numerically-indexed value collections?
If you want to match only arrays:
PS> $x = 1..10
PS> $x.GetType().IsArray
True
or you can check there is integer indexer:
(Get-Member -InputObject $x -Name 'Item' -MemberType 'ParameterizedProperty').Definition -match '\(int index\)'

Difference not taking the difference of everything?

I have two pieces v-piece and i-piece which are joined together with join_pieces().
Afterwards, the combination of those two pieces are meant to be differenced as a whole by two cubes in the piece() function.
The problem is the only piece showing a difference is the i_piece and not the v_piece which even though it is connected, it is left whole with no subtraction. I have removed the difference() line and checked to make sure the cubes are intersecting both pieces and they are. I have tried a union in case the difference was only accepting one object but it appears to not have changed anything.
Any suggestions, or answers to try? Thanks.
module join_pieces() {
union() {
v_piece();
translate([0,0,-1*stem_height+INSERT]) {
i_piece();
}
}
}
module piece() {
difference() {
join_pieces();
rotate([0,0,45]) {
cube([AIR,V_PIECE_WIDTH*4, RADIUS], center=true);
}
rotate([0,0,135]) {
cube([AIR,V_PIECE_WIDTH*4, RADIUS], center=true);
}
}
}
piece();
Could you show the variable definitions and the other functions used by these modules? I tried running your code with cubes replacing v_piece and i_piece and putting random numbers as the variables. It seems like your code is correct for what you want to do, running the modified version:
module join_pieces() {
union() {
translate([-2, 0, 0]){
#cube([5, 2, 2]);
}
translate([0,-2,-1*3+2]) {
cube([3, 5, 3]);
}
}
}
module piece() {
difference() {
join_pieces();
rotate([0,0,45]) {
cube([1,3*4, 4], center=true);
}
rotate([0,0,135]) {
cube([1,3*4, 4], center=true);
}
}
}
piece();
You can see that what you have here is fine.
Have you made sure none of your other functions are missing a semi-colon and used the # to display your difference pieces?

How can I quickly find VMs with serial ports in PowerCLI

I have a script that takes about 15 minutes to run, checking various aspects of ~700 VMs. This isn't a problem, but I now want to find devices that have serial ports attached. This is a function I added to check for this:
Function UsbSerialCheck ($vm)
{
$ProbDevices = #()
$devices = $vm.ExtensionData.Config.Hardware.Device
foreach($device in $devices)
{
$devType = $device.GetType().Name
if($devType -eq "VirtualSerialPort")
{
$ProbDevices += $device.DeviceInfo.Label
}
}
$global:USBSerialLookup = [string]::join("/",$ProbDevices)
}
Adding this function adds an hour to the length of time the script runs, which is not acceptable. Is it possible to do this in a more efficient way? All ways I've discovered are variants of this.
Also, I am aware that using global variables in the way shown above is not ideal. I would prefer not to do this; however, I am adding onto an existing script, and using their style/formatting.
Appending to arrays ($arr += $newItem) in a loop doesn't perform well, because it copies all existing elements to a new array. This should provide better performance:
$ProbDevices = $vm.ExtensionData.Config.Hardware.Device `
| ? { $_.GetType().Name -eq 'VirtualSerialPort' } `
| % { $_.DeviceInfo.Label }

PowerShell - execute script block in specific scope

I am trying to implement RSpec/Jasmine like BDD framework in Powershell (or at least research the potential problems with making one).
Currently I am having problems with implementing simple before/after functionality. Given
$ErrorActionPreference = "Stop"
function describe()
{
$aaaa = 0;
before { $aaaa = 2; };
after { $aaaa; }
}
function before( [scriptblock]$sb )
{
& $sb
}
function after( $sb )
{
& $sb
}
describe
the output is 0, but I would like it to be 2. Is there any way to achieve it in Powershell (short of making $aaaa global, traversing parent scopes in script blocks till $aaaa is found, making $aaaa an "object" and other dirty hacks:) )
What I would ideally like is a way to invoke a script block in some other scope but I don't have a clue whether it is possible at all. I found an interesting example at https://connect.microsoft.com/PowerShell/feedback/details/560504/scriptblock-gets-incorrect-parent-scope-in-module (see workaround), but am not sure how it works and if it helps me in any way.
TIA
The call operator (&) always uses a new scope. Instead, use the dot source (.) operator:
$ErrorActionPreference = "Stop"
function describe()
{
$aaaa = 0;
. before { $aaaa = 2; };
. after { $aaaa; }
}
function before( [scriptblock]$sb )
{
. $sb
}
function after( $sb )
{
. $sb
}
describe
Note the use of . function to invoke the function in same scope as where `$aaaa is defined.

more than one defaction in the body?

All, can I run more than one defaction in the body of the rule? or can I only run one?
You can define as many actions in the pre block of a rule as you want. You can have as many actions in the action block of a rule as you want (just enclose the action block in curly braces). For example,
rule first_rule {
select when pageview ".*" setting ()
pre {
notify_one = defaction() { notify("notify_one", "First defaction"); };
notify_two = defaction() { notify("notify_two", "Second defaction"); };
}
{
notify_one();
notify_two();
}
}
So I think the answer to your question is yes.
Your question is a little confusing, but I'll give it a run.
Running actions defined with defaction is just like running system defined actions.
If you want to run more then one action in a rule, you need to wrap them in {} like so:
rule foo {
select when pageview ".*"
{
notify("cheese", "brie");
notify("apple", "golden delicious");
}
}
I seem to recall that a defaction has an implicit, optional 'pre' section, followed by the action(s). To include multiple actions you do need {} as Sam says.
act1 = defaction() {
{
notify("Defaction Demo", "<ul id='demo_id'></ul>");
append("#demo-id", "<li>cheese: brie</li>");
append("#demo-id", "<li>apple: golden delicious</li>");
}
};
That works out to defaction() { { ... } }; but the extra curly braces are required if you want more than one action in a defaction.
See also http://docs.kynetx.com/docs/Defaction