www.happysysadm.com Open in urlscan Pro
2a00:1450:4001:810::2013  Public Scan

Submitted URL: http://happysysadm.com/
Effective URL: http://www.happysysadm.com/
Submission: On July 05 via api from GB — Scanned from GB

Form analysis 0 forms found in the DOM

Text Content

HAPPY SYSADM

Resources, solutions and tips for system administrators





MONDAY, JANUARY 7, 2019


ARTIFICIAL NEURAL NETWORKS IN POWERSHELL - PART 1


Neural Networks had their beginnings in 1943 when Warren McCulloch, a
neurophysiologist, and a young mathematician, Walter Pitts, wrote a paper on how
human neurons might work.
They focused on understanding how our brain can produce highly complex patterns
by using many basic cells that are bound together. These basic brain cells
are known as neurons, and McCulloch and Pitts imagined a highly simplified model
of a neuron in their paper. The McCulloch and Pitts model of a neuron, also
known as MCP neuron for short, has made an important contribution to the
development of Artificial Neural Networks (ANN), which model key features of
biological brain neurons.
A few years later, in 1958, Frank Rosenblatt, a neuro-biologist, proposed the
Perceptron. The Perceptron is an algorithm for supervised learning of binary
classifiers. In other words it is a function that, given a vector of inputs, is
able to classify them into a class.
Today I am going to start a series of posts that will explain how to rewrite a
Perceptron in PowerShell and that is meant to show how a single node of a neural
network works and can be trained following the model defined by Rosenblatt. All
of this in PowerShell.




But before we proceed, we’ll need to have a look at how a Perceptron does work.
And before we do so, let’s see how we can mathematically emulate a neuron whose
functioning can be represented with the following diagram:



As you can see here, and to simplify things, know that a neuron takes a vector
of inputs, $m1 ,$m2 ,$m... and produces an output by multiplying each input
to different weights, which are real numbers expressing the importance of each
input to the output.

Multiplying those weights by the input allows to decide whether a neuron fires
or not.
In PowerShell the first thing to do is to define an Invoke-Neuron function which
does exactly that, multiplying each input with a pseudo-random weight (notice
the SetSeed parameter used during the generation of the first random weight):




The values of the weight parameters are initialized randomly (this stops them
all converging to a single value). We will see later that when training starts
and the Perceptron is presented with a dataset, those weights are adjusted
towards values that give correct output.
As you can notice, in this function we have to call some kind of activation
function, meaning a function that decides whether the neuron fires (in case the
result approaches 1 or is 1) or not (in case the output approaches 0 or is 0).
Different activation functions exist. McCullogh and Pitts adopted the Heaviside
function, which is used for something called Logistic Regression, meaning that
the function will produce a binary output: the function produces 1 (or true)
when input passes threshold limit whereas it produces 0 (or false) when input
does not pass threshold. In context of pattern classification, such an algorithm
can be useful to determine if a sample belongs to one class or the other, hence
the name binary classifier.
This Heaviside step function can be represented as




and translates to PowerShell as a simple Switch-based function:




The alternative is to use a Non Linear Sigmoid function




which works perfectly to reduce the output to a number between 0 and 1, whatever
the input numbers:




In this function [math]::Exp returns the number e raised to the power –t, where
e is the unique number whose natural logarithm is equal to one and whose value
is approximately equal to 2.71828.
Let’s focus again on the Invoke-Neuron function.
Let’s add another parameter which takes the name of activation function to use:




The produced output for the same input dataset changes from binary to a value
between 0 and 1:




You have now probably noticed that a $bias variable is added to the computation.
His role is similar to the one of the constant b of a linear function:


which graphs to a straight line. It allows us to slide this line up and down to
fit the prediction with the data better. Without that bias the line will always
goes through the axis origin (0, 0) and you may get a poorer fit.
The $bias is one of the learnable parameters of this model, the others being of
course the weights, as we will see when we will develop a Perceptron in the next
blog post.
Here’s our final code:

$w1 = Get-Random -SetSeed 1 -Minimum 0.01 -Maximum 0.99
$w2 = Get-Random -Minimum 0.01 -Maximum 0.99
$bias = Get-Random -Minimum 0.01 -Maximum 0.99

function Invoke-Neuron ($m1, $m2, $w1 ,$w2, $bias, $activation) {
  $t = $m1*$w1+$m2*$w2+$bias
  switch ($activation) {
        heaviside {Heaviside $t}
        sigmoid {Sigmoid $t}
        Default {Sigmoid $t}
        }
  }
Invoke-Neuron 4 7 $w1 $w2 $bias 'Heaviside'
Invoke-Neuron 4 7 $w1 $w2 $bias 'Sigmoid'

This piece of code acts like a human neuron, with dendrites (the inputs $m1,
$m2), synapsis (the weights $w1, $w2) and a single output which is similar to
the neuron output going through the axon.
Simple isn’t it?
In the next post we will see how we can code a Perceptron in PowerShell, and
we’ll try to understand its role in the guess work to determine the best values
to give to weights and bias.
Stay tuned.

Publié par Carlo à l'adresse 1:56 AM 2 commentaires
Email ThisBlogThis!Share to TwitterShare to FacebookShare to Pinterest
Libellés : neural network, neuron, powershell




TUESDAY, JULY 3, 2018


MVP RENEWAL FOR 2018-2019


I am very honored to be renewed as a Microsoft MVP for 2018-2019 in the category
of Cloud and Datacenter Management. The MVP program recognizes content creators,
code providers, technnical leaders and conference speakers who want to share
their knowledge and broaden the outreach of the platforms they work with.
It is always truly gratifying to receive such an award by Microsoft, a company
that is always moving, and that is surrounded by a great community I am proud to
be part of.
To all my readers, thanks.

Publié par Carlo à l'adresse 4:24 AM 0 commentaires
Email ThisBlogThis!Share to TwitterShare to FacebookShare to Pinterest
Libellés : mvp, mvpbuzz




WEDNESDAY, JUNE 20, 2018


INTRODUCING THE INVOKE-WSUS POWERSHELL FUNCTION


A couple of weeks ago I wrote a blog post on WSUS management with PowerShell.
The post came with a script that could be used to manage automatic approvals of
WSUS patches and updates.

This time I have decided to transform that script in an advanced
PowerShell function named Invoke-WSUS (you can find it on my Github).


This function is kind of jack-of-all-trade: depending on the used parameter set,
it can do a series of actions, as shown in the description and in the help file.


NAME
    Invoke-Wsus
    
SYNOPSIS
    Invoke-Wsus is a function used to manage WSUS.
    
    
SYNTAX
    Invoke-Wsus -ShowApprovalGroups -SettingFile string [commonparameters]
    
    Invoke-Wsus -SettingFile string -WsusName string -WsusPort int32 -WsusSSL -SyncDelay int32 -CleanupDay int32 -SendMail -SMTPServer string -From string -To string> [commonparameters]
    
    Invoke-Wsus -SettingFile string -WsusName string -WsusPort int32 -WsusSSL -SyncDelay int32 -CleanupDay int32 -ShowAll [commonparameters]
    
    Invoke-Wsus -SettingFile string -WsusName string -WsusPort int32 -WsusSSL -SyncDelay int32 -ShowApprovalSchedules [-RunApprovalSchedules] [commonparameters]
    
    Invoke-Wsus -ShowWsusTargetGroups -WsusName string -WsusPort int32 -WsusSSL [commonparameters]
    
    Invoke-Wsus -WsusName string -WsusPort int32 -WsusSSL -ShowLastWsusSync [commonparameters]
    
    Invoke-Wsus -WsusName string -WsusPort int32 -WsusSSL -SyncWsusNow [commonparameters]
    
    Invoke-Wsus -ShowNextPatchTuesday [commonparameters]
    
    Invoke-Wsus -ShowNextSyncTuesday -SyncDelay int32 [commonparameters]
    
    Invoke-Wsus -ShowNextClenaupDay -CleanupDay int32 [commonparameters]
    
    
DESCRIPTION
    Invoke-Wsus is a function that is used to determine the next Patch Tuesday, to sync a
    WSUS server with Microsoft,     to approve patches based on target WSUS groups, and to
    show WSUS target groups configuration.
    

RELATED LINKS

REMARKS
    To see the examples, type: "get-help Invoke-Wsus -examples".
    For more information, type: "get-help Invoke-Wsus -detailed".
    For technical information, type: "get-help Invoke-Wsus -full


Before you can use this function you have to use the Set-ApprovalDelay script to
generate a JSON setting file. This file will contain the list of the approval
schedules and, for each schedule, you will have associated WSUS target computer
groups and the delay in days between the synchronization of your WSUS server and
the actual approval of patches.


Let's take as an example the following JSON settings:


$DelaySettings += [pscustomobject]@{

    Name          = 'Immediate'

    WsusGroup   = 'Standard'

    ApprovalDelay = 1

}

$DelaySettings += [pscustomobject]@{

    Name          = 'OneWeek'

    WsusGroup   = 'Touchy','Critical'

    ApprovalDelay = 7

}

This settings will basically say to the Invoke-Wsus function that
   
 * computers belonging to a WSUS target computer group whose name matches the
   'Standard' word will be patched 1 day after the synchroniezation of your WSUS
   server with Microsoft.
   
 * computers belonging to a WSUS target computer group whose name matches the
   'Touchy' or 'Critical' word will be patched 7 days after the synchroniezation
   of your WSUS server with Microsoft.
   



You can simply adapt these settings to your environment and re-run the
Set-ApprovalDelay script to generate a new setting file for your organization.


Now that you have understood what the configuratrion file is used for, here's a
couple of useful examples that show what the Invoke-Wsus function is capable of.


Example 1: Showing the approval delay per target computer group from the setting
file in a readable way


Invoke-Wsus -ShowApprovalGroups -SettingFile approvaldelaysettings.json' 

Today is 06/20/2018 11:28:05

Name      WsusGroup          ApprovalDelay
----      ---------          -------------
Immediate Standard                       1
OneWeek   {Touchy, Critical}             7

Example 2: Showing the list of target computer groups defined on the WSUS server


Invoke-Wsus -ShowWsusTargetGroups -WsusName 'wsusserver' -WsusPort 8530 -WsusSSL:$false

Today is 06/20/2018 13:26:45

Name                                     Total computers
----                                     ---------------
All Computers                                        381
Mission-Critical-M1                                   37
Mission-Critical-M2                                   35
Standard                                             210
User-Touchy-M1                                        50
User-Touchy-M2                                        49
Unassigned Computers                                   0

Having this information will simplify the work of chosing the words to use in
the setting file to match target computer groups.


Example 3: Showing the next Patch Tuesday (optimistically renamed by Microsoft
to Update Tuesday)


Invoke-Wsus -ShowNextPatchTuesday

Today is 06/20/2018 13:30:27
Next Patch Tuesday will be in 20 days on Tuesday, July 10, 2018

I let you take the time to find out what other actions this advanced function
can perform. The only thing that is really important to understand is that this
Invoke-Wsus function is meant to be scheduled daily on your WSUS Server just
like in the example below:


Invoke-Wsus -ShowApprovalSchedules -SettingFile 'approvaldelaysettings.json' -SyncDelay 13 -RunApprovalSchedules -WsusName 'wsusserver' -WsusPort 8530 -WsusSSL:$false

This basically tell the function to execute the automatic approval of needed
patches and updates for target computer groups based on a delay between Patch
Tuesday, Synchronization day and the delay specified in the setting file.

You could also add a second scheduled task that will inform you by mail of the
actions of the day by using the 'Send Mail' parameter set.


Let me know how it goes for you and if you have any question or improvement to
suggest, feel free to get in touch with me.

Publié par Carlo à l'adresse 5:38 AM 2 commentaires
Email ThisBlogThis!Share to TwitterShare to FacebookShare to Pinterest
Libellés : powershell, wsus



TUESDAY, JUNE 12, 2018


GATHERING WSUS SECURITY MONTHLY QUALITY ROLLUPS WITH POWERSHELL


If you follow me, you know that I've been playing a lot with WSUS in recent days
and have discovered there's an extremely simple way to extract the list of all
the Microsoft Security Monthly Quality Rollups (which include cumulated security
updates and non-security updates) residing on a WSUS server with the help of
PowerShell.
The key cmdlet is Get-WsusUpdate. The Get-WsusUpdate cmdlet gets the Windows
Server Update Services (WSUS) update object with details about existing updates.


$MSupdates  = Get-WsusUpdate

Using Get-Member we can see the returned object type:


$MSupdates  | Get-Member

   TypeName: Microsoft.UpdateServices.Commands.WsusUpdate

Name                               MemberType Definition                    
----                               ---------- ----------                    
Equals                             Method     bool Equals(System.Object obj)
GetHashCode                        Method     int GetHashCode()             
GetType                            Method     type GetType()                
ToString                           Method     string ToString()             
Approved                           Property   string Approved {get;}        
Classification                     Property   string Classification {get;}  
ComputersInstalledOrNotApplicable  Property   int ComputersInstalledOrNotApp
ComputersNeedingThisUpdate         Property   int ComputersNeedingThisUpdate
ComputersWithErrors                Property   int ComputersWithErrors {get;}
ComputersWithNoStatus              Property   int ComputersWithNoStatus {get
InstalledOrNotApplicablePercentage Property   int InstalledOrNotApplicablePe
LanguagesSupported                 Property   System.Collections.Specialized
LicenseAgreement                   Property   string LicenseAgreement {get;}
MayRequestUserInput                Property   bool MayRequestUserInput {get;
MsrcNumbers                        Property   System.Collections.Specialized
MustBeInstalledExclusively         Property   bool MustBeInstalledExclusivel
Products                           Property   System.Collections.Specialized
Removable                          Property   bool Removable {get;}         
RestartBehavior                    Property   string RestartBehavior {get;} 
Update                             Property   Microsoft.UpdateServices.Admin
UpdateId                           Property   string UpdateId {get;}        
UpdatesSupersededByThisUpdate      Property   System.Collections.Specialized
UpdatesSupersedingThisUpdate       Property   System.Collections.Specialized

The key point here is that Get-WindowsUpdate used with no parameters reports
patch information of the computer where it runs, which is just a subset of all
the possible patches.

If you want to retrieve the list of all the patches hosted by your WSUS server
here's the syntaxt to use:



$MSupdates = Get-WsusUpdate -Verbose -Approval AnyExceptDeclined

Once you got that (it can take a while, and you'll se the WSUS database pretty
busy), you can easily select the patches that are Security Monthly Quality
Rollups:



$MSupdates.Update |

    ? Title -match 'Security Monthly Quality Rollup' |

    Format-Table title

Title
-----
2018-03 Security Monthly Quality Rollup for Windows Server 2012 R2...
2018-03 Security Monthly Quality Rollup for Windows Server 2012 fo...
2018-03 Security Monthly Quality Rollup for Windows 7 for x64-base...
2018-03 Security Monthly Quality Rollup for Windows Server 2008 R2...
2018-03 Security Monthly Quality Rollup for Windows 7 for x86-base...

As you can see the monthly rollups I see here is the one from last March Patch
Tuesday (KB4088876).

I could think of counting all these Monthly Rollups by OS:



$MSupdates.Update |

    ? Title -match 'Security Monthly Quality Rollup' |

    Group ProductTitles | Select Name,Count | Sort -Descending

All you need to know is simply what kind of patches you want to extract from
this huge list. A few examples now.

Patches whose title starts with 2018:



$MSupdates.Update |

    ? Title -match '^2018' |

    Formaat-table title, creationdate, knowledgebasearticles, producttitles, state

Patches whose title starts with 2017-12 (in this regex the caret ^ matches the
position before the first character in the string):



$MSupdates.Update |

    ? Title -match '^2017-12' |

    Format-Table title, creationdate, knowledgebasearticles, producttitles, state

Patches with a certain KB number:



$MSupdates.Update |

    ? KnowledgebaseArticles -match '4088876' |

    Format-Table title, creationdate, knowledgebasearticles, producttitles, state

Stay tuned for more PowerShell and get ready for today's Patch Tuesday!

Publié par Carlo à l'adresse 1:44 AM 0 commentaires
Email ThisBlogThis!Share to TwitterShare to FacebookShare to Pinterest
Libellés : powershell, wsus



WEDNESDAY, JUNE 6, 2018


WSUS MANAGEMENT WITH POWERSHELL


I have recently discovered the work of fellow MVP Adam Marshall who wrote a
fantastic script aimed at cleaning your WSUS servers and decided to adopt it. A
few days later I started thinking to how I could complete his work by adding a
script that could automate the management of patches throughout the year for all
of my servers, so I shouldn't have to manually sync and approve patches.


In this post I will explain how I manage the whole patch process and introduce
my PowerShell script, which I named wsus-operation.ps1 (which you can find on
Github). Sure, this is an on-going work, so I'll try to keep this post updated
with feedbacks from the Community and with all the things I discover over time.


The first step is to understand how to manage the patching process through the
year. Hence the reason that pushed me to spend a good amount of time studying
the calendar to finally draw the circular timeline you see below: it allows easy
visualization of the patching process from Patch Tuesday to the day Adam's
scripts does the monthly cleanup after all the patches have been deployed.



Supposing that today it's June, 5th, next Patch Tuesday will happen in 7 days on
Tuesday, June 12, 2018: Patch Tuesday comes the second Tuesday of the month so
for sure we will have to include in our script a few lines of code to calculate
it correctly.


After Patch Tuesday, it's a best practice to wait roughly a couple of weeks
before synching your WSUS server, then existing Domain Group Policy (GPO) should
intervene and patch servers following their criticality.


A typical way of doing is to safely sync your WSUS with Microsoft on the fourth
Monday of the month (aliased to FM in the circular timeline).


The day after the sync (FM + 1 day) you could auto-approve needed patches for
standard non-critical servers, then a GPO configured in 'Auto download and
schedule the install' mode could fire the installation every Wednesday (which is
always FM + 2 days) so that those servers actually get the patches and are
eventually rebooted.







For touchy and critical servers, you could approve one week after the sync (FM +
7 days) and set the corresponding GPO configured in 'Notify for download and
notify for install' mode, so that nothing actually happen on the servers until
you are 100% sure those patches don't impact negatively your environment (i.e.
in case of a bug).







In the end you would configure AdamJ script to perform the monthly cleanup of
the WSUS database on the 7h of the month following Patch Tuesday so you have
plenty of time to manually patch your most critical servers.


That could be resumed to:


 * Patch Tuesday (PT)
 * Sync WSUS avec Windows Update on fourth Monday (FM) (PT + 13 days)
 * Approve for non-critical servers (FM + 1 day)
 * GPO schedule the install on non-critical servers on Wednesday (FM + 2 days)
 * Approve for touchy and critical servers (FM + 7 days)
 * GPO notify new patches to touchy and critical servers (FM + 8 days)
 * Adam's scripts clean up old computers and superseded patches (7th of
   following month)



Actually, you have to know that Adam's script runs different actions whether
it's a standard daily run, a monthly run or a quarterly run (on January, April,
July and October).


Here's the actions performed by AdamJ script which daily:


 * Declines Multiple Types of Updates Stream
 * Cleans Up WSUS Synchronization Logs
 * Cleans up Computer Object
 * Performs WSUS DB Maintenance
 * Performs WSUS Server Cleanup Wizard



The same script is also in charge of monthly:
 * Cleaning All daily tasks
 * Removing Obsolete Updates
 * Compressing Update Revisions



Furthermore, on a quarterly basis, the same script:
 * Cleans all daily and monthly tasks
 * Removes WSUS Drivers
 * Removes Declined WSUS Updates



So back to my script now. Here's an explanation of the most relevant parts.




Everything starts with retrieving the current day and putting it in a variable
which I will reuse:


$now = Get-Date


Here's how I decided to calculate the next Patch Tuesday:


$d0 = Get-Date -Day 1 -Month $($now.Month) -Year $now.Year

switch ($d0.DayOfWeek){

        "Sunday"    {$patchTuesday0 = $d0.AddDays(9); break}

        "Monday"    {$patchTuesday0 = $d0.AddDays(8); break}

        "Tuesday"   {$patchTuesday0 = $d0.AddDays(7); break}

        "Wednesday" {$patchTuesday0 = $d0.AddDays(13); break}

        "Thursday"  {$patchTuesday0 = $d0.AddDays(12); break}

        "Friday"    {$patchTuesday0 = $d0.AddDays(11); break}

        "Saturday"  {$patchTuesday0 = $d0.AddDays(10); break}

     }

$d1 = Get-Date -Day 1 -Month $($now.Month + 1) -Year $now.Year

switch ($d1.DayOfWeek){

        "Sunday"    {$patchTuesday1 = $d1.AddDays(9); break}

        "Monday"    {$patchTuesday1 = $d1.AddDays(8); break}

        "Tuesday"   {$patchTuesday1 = $d1.AddDays(7); break}

        "Wednesday" {$patchTuesday1 = $d1.AddDays(13); break}

        "Thursday"  {$patchTuesday1 = $d1.AddDays(12); break}

        "Friday"    {$patchTuesday1 = $d1.AddDays(11); break}

        "Saturday"  {$patchTuesday1 = $d1.AddDays(10); break}

     }

if($now.date -le $patchTuesday0.date){

    $patchTuesday = $patchTuesday0}else{$patchTuesday = $patchTuesday1

    }


The very same code is used to calculate the next Fourth Monday, which is the
days I suggest you sync your WSUS with Microsoft:


$d0 = Get-Date -Day 1 -Month $($now.Month) -Year $now.Year

switch ($d0.DayOfWeek){

        "Sunday"    {$FourthMonday0 = $d0.AddDays(22); break}

        "Monday"    {$FourthMonday0 = $d0.AddDays(21); break}

        "Tuesday"   {$FourthMonday0 = $d0.AddDays(20); break}

        "Wednesday" {$FourthMonday0 = $d0.AddDays(26); break}

        "Thursday"  {$FourthMonday0 = $d0.AddDays(25); break}

        "Friday"    {$FourthMonday0 = $d0.AddDays(24); break}

        "Saturday"  {$FourthMonday0 = $d0.AddDays(23); break}

     }

    
$d1 = Get-Date -Day 1 -Month $($now.Month + 1) -Year $now.Year

switch ($d1.DayOfWeek){

        "Sunday"    {$FourthMonday1 = $d1.AddDays(22); break}

        "Monday"    {$FourthMonday1 = $d1.AddDays(21); break}

        "Tuesday"   {$FourthMonday1 = $d1.AddDays(20); break}

        "Wednesday" {$FourthMonday1 = $d1.AddDays(26); break}

        "Thursday"  {$FourthMonday1 = $d1.AddDays(25); break}

        "Friday"    {$FourthMonday1 = $d1.AddDays(24); break}

        "Saturday"  {$FourthMonday1 = $d1.AddDays(23); break}

     }

if($now.date -le $FourthMonday0.date){

    $FourthMonday = $FourthMonday0}else{$FourthMonday= $FourthMonday1

    }


On top of this last portion of code I built a calculation for the days when I
approve patches both for non-critical and critical servers. Here's the code:


if($now.date -le $FourthMonday0.adddays(1).date){

    $StandardApprovalDay = $FourthMonday0.AddDays(1)}else{$StandardApprovalDay= $FourthMonday1.AddDays(1)

    }

if($now.date -le $FourthMonday0.adddays(1).date){

    $CriticalApprovalDay = $FourthMonday0.AddDays(7)}else{$CriticalApprovalDay= $FourthMonday1.AddDays(7)

    }


Then all the possible conditions have to be evaluated so that proper actions are
executed. If no actions are to be executed, then we just display a message.


if($now.date -eq $PatchTuesday.date){

    "==> It's patch Tuesday!`n"

    }

else {

    "Next Patch Tuesday is in $((New-TimeSpan -Start $now.date -End $patchTuesday.date).days) days on $($patchTuesday.ToLongDateString())`n"
    
    }


if($now.date -eq $FourthMonday.date){

    (Get-WsusServer).GetSubscription().StartSynchronization()

    }

else {

    "Next Sync will happen in $((New-TimeSpan -Start $now.date -End $FourthMonday.date).days) days on $($FourthMonday.ToLongDateString())`n"
    
    }


Before we continue, a quick note about WSUS group assignment: you really should
enable Client Side Targeting in your WSUS GPO so that you are assured that your
servers will automatically fall in the right WSUS groups.






In my case I have configured targeting of non-critical servers in a group named
'standard servers' and targeting of touchy and critical servers in groups named
'touchy servers' and 'critical servers'.


In the following part I am using the Approve-WsusUpdate cmdlet to
approve unapproved patches that are needed by servers residing in WSUS groups
that match the word 'standard' in their names:


if($now.date -eq $StandardApprovalDay.date){

    "==> It's the day after fourth monday of the month - approving for Standard servers`n"

    $wsus = Get-WsusServer

    $allupdates = $wsus.GetUpdates() 

    $alltargetgroups = $wsus.GetComputerTargetGroups()

    $computergroups = ($alltargetgroups | ? name -match 'Standard').name

    $computergroups | % {

        Get-WsusUpdate -Approval Unapproved -Status FailedOrNeeded | Approve-WsusUpdate -Action Install -TargetGroupName $_ –Verbose

        }

    }

else {

    "Next approval for Standard servers will happen in $((New-TimeSpan -Start $now.date -End $StandardApprovalDay.Date).days) days on $($StandardApprovalDay.ToLongDateString())`n"
    
    }


In the following part I am approving needed unapproved patches for servers
residing in WSUS groups that have the words 'touchy' or 'critical' in their
names:


if($now.date -eq $CriticalApprovalDay.date){

    "==> It's the 7th day after fourth monday of the month - approving for User-Touchy and Mission-Critical servers`n"

    $wsus = Get-WsusServer

    $allupdates = $wsus.GetUpdates() 

    $alltargetgroups = $wsus.GetComputerTargetGroups()

    $computergroups = ($alltargetgroups | ? name -match 'touchy|critical').name

    $computergroups | % {

        Get-WsusUpdate -Approval Unapproved -Status FailedOrNeeded | Approve-WsusUpdate -Action Install -TargetGroupName $_ –Verbose

        }

    }

else {

    "Next approval for User-Touchy and Mission-Critical servers will happen in $((New-TimeSpan -Start $now.date -End $CriticalApprovalDay.date).days) days on $($CriticalApprovalDay.ToLongDateString())`n"
    
    }


if($now.day -eq 7){

    "==> Today is WSUS monthly clean up day`n"

    }

else{

    "Next WSUS monthly clean up will happen in $((New-TimeSpan -Start $now.date -End $(Get-Date -Day 7 -Month $($now.Month + 1) -Year $now.Year -OutVariable datenextcleanup).Date).Days) days on $($datenextcleanup.ToLongDateString())`n"

    }


As you can see, coupling those actions with well configured group policies and
with Adam's script will make your WSUS installation agile and pretty automated.


Of course this approach can be improved and if I find better ways of doing I
won't hesitate to update the PowerShell script on GitHub as well as this post. I
hope that the community will contribute to the improvement of this script based
on its experience, so that this can benefit the Community and will make WSUS
admins less prone to headache.




If you liked this post, feel free to share.




UPDATE June, 11th 2018: This post got a lot of feedbacks, and there is an
optimization in particular that made it to the master branch on GiHub: I'd like
to thank CleverTwain (reddit github) for making my script more modular. He made
a few nice additions such as:


Moving parameters and general settings to the top:


$action = $false

$now = Get-Date

$comments = "Today is $($now.ToLongDateString())`n"

$WSUSServerParams = @{

    Name   = 'wsusserver'

    Port   = 8530

    UseSSL = $false

}

# Moved these to the top as others may want to tweak as necessary

$SyncDelay = 13 # How many days after Patch Tuesday should we wait before syncing WSUS

$WSUSCleanUpDay = 7 # What numerical day of the month whould the WSUS cleanup script run?

# Changed delay settings to use objects, as that is the most flexible

$DelaySettings = @()

$DelaySettings += [pscustomobject]@{

    Name          = 'Immediate'

    # Now multiple collections can share the same delay settings without adding multiple checks

    Collections   = 'Standard', 'NonCritical'

    ApprovalDelay = 1

}

$DelaySettings += [pscustomobject]@{

    Name          = 'OneWeek'

    Collections   = 'Touchy', 'Critical'

    ApprovalDelay = 7

}

Making Fourth Monday calculation dependant from Patch Tuesday through a
SyncDelay variable that WSUS admins can set according to their internal policy:


$firstOfThisMonth = (Get-Date -Day 1 )

switch ( $firstOfThisMonth.DayOfWeek ) {

    "Sunday" {$thisPatchTuesday = $firstOfThisMonth.AddDays(9)}

    "Monday" {$thisPatchTuesday = $firstOfThisMonth.AddDays(8)}

    "Tuesday" {$thisPatchTuesday = $firstOfThisMonth.AddDays(7)}

    "Wednesday" {$thisPatchTuesday = $firstOfThisMonth.AddDays(13)}

    "Thursday" {$thisPatchTuesday = $firstOfThisMonth.AddDays(12)}

    "Friday" {$thisPatchTuesday = $firstOfThisMonth.AddDays(11)}

    "Saturday" {$thisPatchTuesday = $firstOfThisMonth.AddDays(10)}

}

if ($now.date -le $thisPatchTuesday.date) {
    $patchTuesday = $thisPatchTuesday
   
}
else {
    $firstOfNextMonth = (Get-Date -Day 1 -Month ((Get-Date).AddMonths(1).Month) )

    switch ( $firstOfNextMonth.DayOfWeek ) {

        "Sunday" {$patchTuesday = $firstOfNextMonth.AddDays(9); break}

        "Monday" {$patchTuesday = $firstOfNextMonth.AddDays(8); break}

        "Tuesday" {$patchTuesday = $firstOfNextMonth.AddDays(7); break}

        "Wednesday" {$patchTuesday = $firstOfNextMonth.AddDays(13); break}

        "Thursday" {$patchTuesday = $firstOfNextMonth.AddDays(12); break}

        "Friday" {$patchTuesday = $firstOfNextMonth.AddDays(11); break}

        "Saturday" {$patchTuesday = $firstOfNextMonth.AddDays(10); break}

    }
}

$SyncDay = (Get-Date -Date $patchTuesday).AddDays($SyncDelay)

Gathering all WSUS patch information once and once only:


# Getting this once now, rather than for each iteration....

$wsus = Get-WsusServer @WSUSServerParams

$allupdates = $wsus.GetUpdates()

$alltargetgroups = $wsus.GetComputerTargetGroups()

$NeededUpdates = Get-WsusUpdate -Approval Unapproved -Status FailedOrNeeded

So thanks to him for these contributions. The updated script can be found
here. That is exactly what being part of a technical community should be like.


UPDATE June, 14th 2018: Added a few more date conditions so that when the script
runs between approvals, it is able to handle correctly the action to do. Added
also a few minor fixes. Find the updated code on GitHub.


UPDATE June, 20th 2018: Published the Invoke-Wsus advanced PowerShell function
which improves and replaces the wsus-operations.ps1 script.

Publié par Carlo à l'adresse 6:46 AM 1 commentaires
Email ThisBlogThis!Share to TwitterShare to FacebookShare to Pinterest
Libellés : powershell, wsus



MONDAY, FEBRUARY 12, 2018


HOW TO USE POWERSHELL TO SOLVE WSUS ERROR 0X80244022


Recently I have started seeing my WSUS clients returning error 0x80244022 during
the classic Windows Update checks.



At first I tought there was some kind of bug on my clients, then, once I checked
my WSUS server, I came across an error message on the patch management console
which stated I had to perform a Node Reset for the WSUS service to get back
online.


After a bit of digging, I discovered that the WSUS pool is configured with a
hardcoded Private Memory Limit set to 1843200 (which is 1.8 GB). Further
analysis made me realize that each time that memory limit is reached, the IIS
pool simply stops, breaking my WSUS service.

Needless to say, I decicded to try and solve this issue using my favorite tool:
PowerShell.


So I produced a quick and dirty PowerShell script that increases that private
memory limit to 8 GB, which should be enough for this kind of service.


Here's the code:

Import-Module WebAdministration
$NewPrivateMemoryLimit = 8388608
$ApplicationPoolsPath = "/system.applicationHost/applicationPools"
$ApplicationPools = Get-WebConfiguration $applicationPoolsPath
    foreach ($AppPool in $ApplicationPools.Collection) {
     if ($AppPool.name -eq 'WsusPool') {
      $AppPoolPath = "$ApplicationPoolsPath/add[@name='$($AppPool.Name)']"
      $CurrentPrivateMemoryLimit = (Get-WebConfiguration "$AppPoolPath/recycling/periodicRestart/@privateMemory").Value
            "Private Memory Limit for $($AppPool.name) is currently set to: $($CurrentPrivateMemoryLimit/1000) MB"
            Set-WebConfiguration "$AppPoolPath/recycling/periodicRestart/@privateMemory" -Value $NewPrivateMemoryLimit
            "New Private Memory Limit for $($AppPool.name) is: $($NewPrivateMemoryLimit/1000) MB"
            Restart-WebAppPool -Name $($AppPool.name)
            "Restarted the $($AppPool.name) Application Pool to apply changes"
            }
     }

Once you run this piece of code on your WSUS server, the application pool gets
restarted and your WSUS will have happy access to an increased memory space:






If you look at the following Resource Monitor screenshot you will see that the
actual used memory becomes in my case a bit more of 2 GB, which is larger than
the default 1.8 GB value but smaller than the 8 GB I set, so I'm fine:



Stay tuned for more PowerShell.

Publié par Carlo à l'adresse 3:50 PM 0 commentaires
Email ThisBlogThis!Share to TwitterShare to FacebookShare to Pinterest
Libellés : powershell, wsus



FRIDAY, FEBRUARY 2, 2018


POWERSHELL ONELINER TO LIST ALL THE INSTALLED .NET VERSIONS ON A REMOTE COMPUTER


Not so long ago I described how to retrieve the installed .NET version in a
single line of PowerShell code through a registry query. This time I want to
show you how the same can be achieved on a remote system by modifying a bit our
approach. The big difference is that for a remote instance you have to access
the HKEY_LOCAL_MACHINE base key through the RegistryKey.OpenRemoteBaseKey
method.

The key path is the same as the one we saw on the locally run oneliner:


HKLM\SOFTWARE\Microsoft\NET Framework Setup\NDP




The regular expression is moved at the beginning of the oneliner, so that I can
cycle through every item and open one subkey at the time.

"v1.1.4322","v2.0.50727","v3.0","v3.5","v4\Full"|%{([Microsoft.Win32.RegistryKey]::OpenRemoteBaseKey('LocalMachine', $Computer)).OpenSubKey("SOFTWARE\Microsoft\NET Framework Setup\NDP\$_").GetValue('version')}

As you can see with a bit of PowerShell gymnastics, you can get pretty concise
lines of code that do powerful things.
Stay tuned for more PowerShell.

Publié par Carlo à l'adresse 1:43 AM 4 commentaires
Email ThisBlogThis!Share to TwitterShare to FacebookShare to Pinterest
Libellés : dotnet, powershell



THURSDAY, DECEMBER 21, 2017


CONFIGURING VISUAL STUDIO CODE FOR POWERSHELL CORE 6 AFTER EXECUTABLE NAME
CHANGE


That's a quick one before the end of the year. Last october the PowerShell Team,
after a long debate with community members decided to rename the executable of
PowerShell Core 6 from powershell.exe to pwsh.exe.





This allows to easily distinguish PowerShell Core from the PowerShell 5.1 built
into your Windows 10. And now you can execute pwsh on Windows or Linux and get
PowerShell Core 6 in a consistent manner.





Assuming you have moved from the PowerShell ISE to Visual Studio Code and got
the PowerShell Extensions installed, there's a couple setting you have to put in
place so that you can work with pwsh.exe as the default terminal:


   "powershell.powerShellExePath": "c:/Program
Files/PowerShell/6.0.0-rc.2/pwsh.exe",
   "terminal.integrated.shell.windows": "c:/Program
Files/PowerShell/6.0.0-rc.2/pwsh.exe"


The year 2017 is almost over. If you haven't yet played with the beta of
PowerShell Core, I heartedly suggest you to do so, so that you can start getting
used with a cross-platform shell available for Linux, Mac or Windows. You can
find it open sourced here.


If you still stick with the PowerShell ISE, you should give a try to Visual
Studio Code, which you can download here. For those of you familiar with the
ISE, there's a great video tutorial by fellow MVP Mike F Robbins which shows you
how to make your Visual Studio Code ISE-like. Just add the two settings above
and you'll get a familiar environment ready for PowerShell Core.


Publié par Carlo à l'adresse 3:20 AM 0 commentaires
Email ThisBlogThis!Share to TwitterShare to FacebookShare to Pinterest
Libellés : core, powershell



MONDAY, DECEMBER 18, 2017


POWERSHELL ONELINER TO LIST ALL THE INSTALLED .NET VERSIONS ON A LOCAL COMPUTER


In my drawers of PowerShell tools, I have a pretty extensive list of oneliners I
have written for specific tasks. Today I want to share the line of code I wrote
to check the .NET version installed on a local system. Since there is no direct
method to find that information, a lot of people have come up with advanced
functions, which is a bit overkill to me. So, given the fact that I like playing
with the pipeline, and that I needed a quick and dirty script for this, I
decided to see if I could find a way to get this done in just one line of code.


Starting from .NET 1.1 the registry key where the list of installed frameworks
is installed is found under:

HKLM\SOFTWARE\Microsoft\NET Framework Setup\NDP

Under this key, you'll see separate keys for each .NET Framework version
installed in your system.



Possible paths are:


1.1 HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\NET Framework Setup\NDP\v1.1.4322
2.0 HKEY_LOCAL_MACHINE\Software\Microsoft\NET Framework Setup\NDP\v2.0.50727
3.0 HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\NET Framework Setup\NDP\v3.0
3.5 HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\NET Framework Setup\NDP\v3.5
4.0 HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\NET Framework Setup\NDP\v4\Full
4.5 HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\NET Framework Setup\NDP\v4\Full
4.5.1 HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\NET Framework Setup\NDP\v4\Full
4.5.2 HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\NET Framework Setup\NDP\v4\Full
4.6 HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\NET Framework Setup\NDP\v4\Full
4.6.1 HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\NET Framework Setup\NDP\v4\Full
4.6.2 HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\NET Framework Setup\NDP\v4\Full

As you can see, there are five possible unique paths.

These can be matched with a regular expression:


v1.1.4322$|v2.0.50727$|v3.0$|v3.5$|v4\\Full$

which excludes v4.0 because it is deprecated.

Having PowerShell native access to the registry, we can run the following line
on our local computer:


ls 'HKLM:\SOFTWARE\Microsoft\NET Framework Setup\NDP'

just like you'd be browsing your file system.

Now what you have to know is that each .NET framework has a version name and a
version number:

 * .NET version name is composed by digits, and comes with the product name i.e.
   .NET 2.0, .NET 3.5, .NET 4.7.1
 * .NET Version number follows this convention: (Major version).(Minor
   version).(Revision number).(Build number)


Here's some version numbers I have in my environment:


 * 4.7.02053
 * 4.5.51209
 * 3.5.30729.01
 * 2.1.21022


As you can see version names and version numbers share the first two fields. So,
for istance, .NET 4.7.1 has version number 4.7.02556. We can then say that we
don't care about the revision or build numbers (third and fourth field). The
first two fields are all that I need.

To make a long story short, here's the PowerShell oneliner that I need to run to
locally get all the installed .NET releases:


((ls 'HKLM:\SOFTWARE\Microsoft\NET Framework Setup\NDP' -rec|? name -match 'v1.1.4322$|v2.0.50727$|v3.0$|v3.5$|v4\\Full$').name -replace 'HKEY_LOCAL_MACHINE','HKLM:'|%{ Get-ItemProperty $_}).Version

Hope this helps guys. Let me know in the comments if somebody here is able to
make my oneliner shorter.

UPDATE: On older PowerShell version use:


((ls 'HKLM:\SOFTWARE\Microsoft\NET Framework Setup\NDP' -rec|? {$_.name -match 'v1.1.4322$|v2.0.50727$|v3.0$|v3.5$|v4\\Full$'} | select -expand name) -replace 'HKEY_LOCAL_MACHINE','HKLM:') -replace 'HKEY_LOCAL_MACHINE','HKLM:'|%{ Get-ItemProperty $_} | select -expand Version


UPDATE: You can also specify this registry path by specifying the registry
provider's name, followed by "::". The registry provider's full name is
Microsoft.PowerShell.Core\Registry, but this can be shortened to just Registry.
So the following syntax is also possible


((ls 'HKLM:\SOFTWARE\Microsoft\NET Framework Setup\NDP' -rec|? name -match 'v1.1.4322$|v2.0.50727$|v3.0$|v3.5$|v4\\Full$').name |%{ Get-ItemProperty "Registry::$($_)"}).Version


Publié par Carlo à l'adresse 1:13 AM 4 commentaires
Email ThisBlogThis!Share to TwitterShare to FacebookShare to Pinterest
Libellés : dotnet, powershell



TUESDAY, DECEMBER 5, 2017


POWERSHELL ONELINERS BY GUEST BLOGGER BRIAN


During the latest PowerShell Oneliner Contest, Brian came up with a solution to
Task 3 which is completely fantastic: he makes a very smart use of Group-Object
-AsHashTable -AsString as well as of Invoke-Expression to produce an
impressive 187 chars long solution.


Brian as kindly accepted to be my guest blogger today.


First of all, let's have a look at his answers to my PowerShell contest:

TASK 1: MANIPULATING OUTPUT - 43 chars


gwmi Win32_Share|% N*|%{"\\$(hostname)\$_"}

TASK 2: MANDELBROT JOKE - 54 chars


"The B in $(($b=gv q* -v|% s*g 27 20)) stands for $b."

TASK 3: TEXT MINING - 187 chars


$t1,$t2|%{$_-split'\W+'|% *wer|group -ash -ass}-ov h|% K*|sort|gu|%{($d+=($1=$h[0].$_.Count)*($2=$h[1].$_.Count)),($a+=$1*$1),($b+=$2*$2)}|%{$m="[math]::Sqrt("}{}{"$d/($m$a)*$m$b))"|iex}


1. Brian, tell us a bit about yourself and about the way you got to work with
PowerShell


I'm a syadmin/SRE/Systems Engineer working mostly on Windows but going cross
platform whenever I can. I got started with PowerShell relatively late; maybe
about 5 years ago now. Before using PowerShell my scripting tasks were mostly
done with Ruby. I really enjoyed it as a language. At one of my previous jobs
PowerShell was in heavy use there (particularly by the Exchange admin) so I
started picking it up and then ran with it.

2. Is there any PowerShell project of your you want to speak about?


I have a module called Idempotion that lets you easily use DSC resources
directly in scripts. It's a templated wrapper around Invoke-DscResource that
gives you more natural PowerShell function syntax and some additional features
(-WhatIf support, etc.).


This is also on the GitHub page but for example, where you would use a line like
this:

Invoke-DscResource -Name File -ModuleName PSDesiredStateConfiguration -Method Set -Property @{ DestinationPath = 'C:\Folder\File.txt' ; Contents = 'Hello' }

Idempotion lets you do this:

Set-File -DestinationPath 'C:\Folder\File.txt' -Contents 'Hello'


3. Can you show us the way you tackled Cosine Similarity Task?


This was a pretty challenging task. I had never heard of cosine similarity
before, so I had to first learn what that was, learn how to apply to it a string
(since it's really about numbers), then come up with an implementation that
could be sufficiently golfed.


My first attempt, at 254 characters defined functions (as ScriptBlocks in
variables) for dot product and vector magnitude, and then called them later once
the full vectors were realized. To make a long story short, it's much better to
calculate the dot product and magnitude as you go along; it just took me a while
to figure out that I could do that with this algorithm.


So actually I want to talk about some of the other challenges.


Unlike traditional code golfing, this is specifically a one-liner contest; so no
newlines and no semicolons. This really forces you think hard about how you can
do discrete tasks (even variable assignment) without stopping for a new
statement. The fact that we're starting with two discrete variables for the
source string puts that problem right up front.


So I start by making an array of $t1 and $t2 with the comma operator and then
pipe that into ForEach-Object.


Splitting the string with \W+ splits on contiguous non-word characters as needed
so that we get an array of words. After that I really want to lowercase version
of the words, and then I want to group them into a hashtable.


To do lowercase, you can call .ToLower() but calling methods directly is painful
in code golf. You need the entire name, need to use parentheses, if the source
is not a variable or literal you also have to wrap the source in parentheses.


Luckily there's a little-known parameter set to ForEach-Object. Instead of
passing a script block, you pass a member name like a property or method and
then it gets retrieved/invoked for each input object. It even takes arguments
for methods. Best of all it accepts wildcards (it must be unambiguous). With
properties, this is like using Select-Object -ExpandProperty, just much shorter
than even select -exp.


So:

("I can't read words."-split'\W+').ToLower()

Can become:


"I can't read words."-split'\W+'|% *wer

I use this extensively in code golf, and I wrote about it in the Tips for
Golfing PowerShell thread on Stack Exchange's Code Golf site.


So you'll see me use this A LOT in this task.


Back to the pipeline: after ToLower I'm using Group-Object with -AsHashTable and
-AsString. You'll see soon why I want a hashtable. -AsString is needed to get
real strings for the hashtbale keys (this is annoying). The purpose of grouping
is to get the the counts of each unique word. Group-Object isn't case sensitive
so we don't actually need ToLower for this; but we need it later.


So the result of this ForEeach-Object is two hashtables, one for each of the
input strings. The keys of each hashtable are the unique words, the values are
an array of each instance of the word. So if the string contained the word
"really" twice, the hashtable would contain a key of "really" with a value of
@('really', 'really').


I'm using the -OutVariable parameter to store the resulting array of hashtables
in a variable named h, while also sending it down the pipeline.


The next part, |% K* uses the aforementioned method of using ForEach-Object to
expand a property. K* resolves to "Keys". This gets passed to sort and gu
(Get-Unique) to get a list of unique keys. Since Get-Unique is case sensitive,
this is why I lowercased the words previously. At this point in the pipeline
though, all we have are keys. The pipeline objects are just strings, and the
original hashtables they came from are not in the pipeline. So that's why I put
them in $h.


The next ForEach-Object does a lot of the "work" here. For each key I'm sending
in, I need to retrieve the count of that key from the first hashtable ($h[0],
which is the words in $t1) and the second hashtable ($h[1], the words in $t2).
So $h[0].$_.Count does that for $t1, where $_ is the current key. These are the
"pairs" of each vector. Doing it this way, with hashtables, ensures I'll get 0
for words that are in one string but not in another. Originally I was just using
groups and missing words because of that. I'm going to need each of these values
3 times so it makes sense to store them in variables. I chose $1 and $2.


Small aside: PowerShell has a neat little quirk whereby you can do an assignment
inside of a substatement (parentheses), and it does the assignment while also
returning the value that was assigned. This also works with += and -=. This is
really critical here.


To calculate the dot product, I need to multiply $1 and $2, and keep adding
those up as I go along. $d holds my dot product. So:

$d+=($1=$h[0].$_.Count)*($2=$h[1].$_.Count)

Keeps accumulating $d with my dot product as I go along, while assigning $1 and
$2 for what comes next in the current iteration.


Within this iteration I also have to accumulate the values for magnitude for
each vector (or at least for the squares of the current vector value). $a and $b
hold the accumulating pre-square root magnitude values for $1 and $t2
respectively.


So I need to do 3 assignments here all within this 1 iteration, without
semi-colons and newlines, so what to do? Let's just make an array of all three
while assigning them, with prodigious use of parentheses and 2 commas!


Now I'm accumulating all the right values at the right time. Problem is, I don't
need this array! I could nullify it, but that's a problem too; if I don't return
anything to the pipeline, the next element won't run its process block.


Instead, the next ForEach-Object uses all 3 blocks, and the Process block is
empty, because at this point I don't care about what's in the pipeline, I just
want to finish the work.


The begin Block was necessary to get to End block, so I kind of got it "for
free". What a perfect place to do another assignment! I'm setting up $m to
contain a string that looks an awful lot like a piece of PowerShell code that
calls [math]::Sqrt(.


In the End block, we bring it all together. What I need to do here is divide the
dot product ($d) by the product of the Sqrt of $a and the Sqrt of $b. I do this
by generating a string which ends up containing something like
"123/([math]::Sqrt(4)*[math]::Sqrt(5))", and then I pipe that into
Invoke-Expression (iex).


An intermediate solution I had assigned [math]::Sqrt (the actual method itself)
to the variable $m, so that I could call $m.Invoke($a) through the shorter $m|%
I* $a, but the stringification with iex is actually way shorter. This kind of
thing comes in handy a lot in golfing.


So that's it! You can find more of my golfing on StackOverflow's golfing site (I
pretty much only use PowerShell there even though they are open to any
language).

Publié par Carlo à l'adresse 1:40 AM 0 commentaires
Email ThisBlogThis!Share to TwitterShare to FacebookShare to Pinterest
Libellés : poshcontest2017, powershell



THURSDAY, NOVEMBER 30, 2017


POWERSHELL ONELINERS BY GUEST BLOGGER SIMON


During the last PowerShell Oneliner Contest, Simon came up with the shortest
working solution to Task 2, and I am happy to say that he promptly accepted to
be my guest blogger today.

Let's see his three remarkable answers to my PowerShell contest:

TASK 1: MANIPULATING OUTPUT - 46 chars


Gwmi Win32_Share|%{"\\$($_|% P*e)\$($_.Name)"}

TASK 2: MANDELBROT JOKE - 50 chars


gv q* -v|% Su* 26 21|%{"The B in$_ stands for$_."}

TASK 3: TEXT MINING - 196 chars


"$t1 $t2"-split'\W'|group|%{$o=$i=$p=0}{if($q=$_.Name){$1,$2=$t1,$t2|%{($_-split'\W'|group|? name -eq $q).Count}}if($o+=$1*$1){$i+=$2*$2}$p+=$1*$2}{if($3,$4=$o,$i|%{[math]::Sqrt($_)}){$p/($3*$4)}}


1. Simon, tell us a bit about yourself and about the way you got to work with
PowerShell

I'm working as consultant in Sweden helping customers planning and building all
kinds of automation, mainly using PowerShell. With a background in IT support
and IT operations and a strong passion for coding I'm trying to preach developer
practices to the ITPro community such as sourceControl, continuous integration
and testing. Being able to collaborate on PowerShell scripts with your team and
have the scripts automatically tested, signed and delivered to where they can be
run solves a lot of questions like for example: "how do I know this script
hasn't been changed since I ran it last time?".
I started my PowerShell journey quite a few years back when I was in client
management. We had tens of thousands of clients reporting to Altiris and McAfee
ePO and it was my task to sort and delegate actions based on those reports. When
I realized I could parse the reports with PowerShell and do some basic sorting
and filtering, that job got a lot easier and I was sold.

2. Is there any PowerShell project of your you want to speak about?

I think Phosphor (https://github.com/PowerShell/Phosphor) is an amazing project
that hasn't got the attention it deserves. Phosphor can basically do a
Get-Command and generate a web-form for each cmdlet. This could be used as a
cross platform implementation of Show-Command or for building simple
self-service portals. Imaging having a webserver that uses Kerberos Constrained
Delegation to log the user in to a bunch of JEA endpoints and then generate a
form for each command available to that user. This way any PowerShell savvy
person in the Operations team could deliver self-service business value to the
organization without depending on web-developers.
Each time I have an hour of spare time I try to learn some TypeScript so I can
fully understand how Phosphor works and hopefully I can get to contributing to
the project in the future.

3. I was impressed by your solution to Mandelbrot's riddle. Can you explain your
approach to it?

Thank you! I started by trying to find text that was similar in both the
question and the answer and saw that the string " Benoit B. Mandelbrot" was the
longest text I could find in the question that was repeated in the answer.

I started by just figuring out the shortest way to insert that into a string and
got this:

$x = " Benoit B. Mandelbrot"
"The B in$x stands for$x."

Then I tried to find the shortest way to break out my string from the question
and got to this:

$x = $Question.Substring(26,21)
"The B in$x stands for$x."

This looked quite good to me, but I wanted to shorten the substring part. This
took me to one of my favorite code-golf tricks, using Foreach-Object with the
parameter MemberName. Foreach-Object has a not very well known parameter called
MemberName that instead of running a piece of code for each object coming
through the pipeline, it invokes the named member of each object that has such a
member. In this case I want to invoke the member Substring and give it the
arguments 26 and 21 using the parameter ArgumentsList. Like this:

$x = $Question | Foreach-Object -MemberName Substring -ArgumentList 26, 21
"The B in$x stands for$x."

Now this doesn't look shorter, but we can shorten it! Let's look at the
parameters of Foreach-Object using Get-Help:

Get-Help -Name Foreach-Object -Parameter *

This tells us that the MemberName parameter belongs to a set called
PropertyAndMethodSet, let's filter on that set:

Get-Help -Name Foreach-Object -Parameter * | Where-Object -Property parameterSetName -like *PropertyAndMethodSet*

Ok, so we have three parameters:
InputObject accepts pipeline input ByValue and will be bound since we are piping
$Question.
MemberName is a positional parameter with position 0 so the first positional
value/argument will be bound to MemberName. I also happen to know that
MemberName accepts wildcards!
ArgumentList is not positional, but it takes value "FromRemainingArguments"
meaning that all values/arguments that remains after MemberName is bound will be
bound to argument list.
Using Get-Alias we can also find that Foreach-Object has an alias '%'

Get-Alias -Definition Foreach-Object

With this knowledge we can shorten our code significantly:

$x = $Question | % Su* 26 21
"The B in$x stands for$x."

Now that looks good, but $Question is also quite long, what if we could use a
wildcard to get the variable? Let's try with Get-Variable which has an alias of
gv. To get that value of the variable and not the variable itself we also use
the parameter -ValueOnly, but we don't need to write ValueOnly, PowerShell is
happy as long as it can figure out that is what we want. Since ValueOnly is the
only parameter starting with a v, -v is enough.

$x = gv q* -v |  % Su* 26 21
"The B in$x stands for$x."

Let's make this a one-liner using Foreach-Object and replacing $x with $_ and
remove unnecessary spaces and we get this:

gv q* -v|% Su* 26 21|%{"The B in$_ stands for$_."}


4. Do you see any possible scenario where using Cosine Similarity in PowerShell
could help?


Yes absolutely! I'm doing Active Directory migrations and identity projects
where we need to match a user or person in one system with a user in another
system. This is easy as long as we have a common and unique attribute like email
to match on, but when we don't we often need to match on for example givenname
and surname. Using cosine similarity I can find persons with similar names.

Publié par Carlo à l'adresse 5:13 AM 1 commentaires
Email ThisBlogThis!Share to TwitterShare to FacebookShare to Pinterest
Libellés : poshcontest2017, powershell



MONDAY, NOVEMBER 27, 2017


POWERSHELL ONELINERS BY GUEST BLOGGER KA-SPLAM


As you know, the PowerShell Oneliner Contest 2017 has its winner: Ka-Splam, from
UK. Today I am proud to announce that Ka-Splam has accepted to answer a few
questions on this blog.


Take the time to read it all and, if the PowerShell monk in you is able to solve
'The 25 chars contest' hidden in his answers, leave a comment for greater glory.

1. Ka-Splam, it's an honor to have you here today to talk about the the
impressive oneliners you provided. I know that you are very active on the
PowerShell subreddit and regularly competing and winning in Shortest Script
challenges. Let's get straight to the point: how one gets good at those
challenges?


Oneliners take a long time to write, they're often frustrating, they run slowly,
they're hard to read, you shouldn't use them in production scripts, and they
don't handle edge cases or errors. There is no reason you should want to get
involved in them.
Except that they're fun.
If you like that kind of thing - if you enjoy nitpicking over details .. hold up
a moment! Here's a detail to nitpick: shortest code challenges ('codegolf') are
what produces hard to read code. Oneliners are clean, clear, readable – what you
get when you trim away the fluff and use the tools skillfully.
Happysysadm hinted that I should try and write something the community could
learn from, and that's a bit scary; what I'm going to do is solve a simple
problem and then shorten it. In detail. I don't know whether the work of writing
short code has any real-world use, but I'm convinced that if you are engaged in
something (anything), if you are thinking about it, experimenting with it,
trying to shape it to your will - you will learn something.
Short-code challenges keep me engaged, keep me digging into edge cases in my
understanding of the language in a way that classic problems like "write three
pages of code to simulate an object oriented deck of cards" don't. Nobody talked
me into this kind of thing by saying it would be good for me; I have always
liked using built-in tools with no need for 3rd party dependencies, utilities
that consist of a no-install .exe, and reduced "bloat".
Except writing. If you skim read this article and think it's too long - look how
much effort it takes me to shorten this puzzle. Doing that to shorten this blog
post would take weeks! ??
Problem: "things in the root of my C:\ drive, where the name is more than ten
characters, just their names", and the long form code is:

$items = Get-ChildItem –Path 'C:\'
$longNames = @()
$items | ForEach-Object –Process {
    If ($_.Name.Length -gt 10)
    {
        $longNames += $_.Name
    }
}
Foreach ($name in $longNames)
{
    Write-Output $name
}

It is 12 lines and 241 characters, which I will keep track of as we reduce it,
and the output is four strings:

OpenSSL-Win32
Program Files
Program Files (x86)
Python27-32bit

I have made this code a bit laborious, but people familiar with PowerShell
should easily follow what it's doing – there is clear separation of the major
steps: gathering data into a variable. Stop. Checking the name length. Stop.
Collecting the results. Stop. Displaying the output. Stop.
(NB. Beginner programmers will still struggle - there's nothing intuitive from
everyday life about `Get-ChildItem` or syntax like `+=` or `$_.Name.Length` or
piping into `ForEach-Object`, but they are common patterns in PowerShell. As we
shorten the code, we move from common patterns towards rare, novelty patterns).
But I don't want to type so much code to satisfy a momentary curiosity about
folder name length and this is not an engaging or interesting puzzle on its own
- once you've got past the basics of PowerShell there is no challenge. Instead
of looking for a harder puzzle, we can make this more challenging by writing it
in less code. And it's an open ended challenge: there's no fixed place to get
to, no pass or fail, and you're mostly competing against yourself. That's
something I like about it.
How do we write it in less code, what is that process?
You know how putting five numbers in order is easy and people learn how to sort
numbers into order some time during childhood, learning by example? Telling
someone steps to sort five numbers in order is much harder - that's computer
science academic work. Well, I know how to write shorter code but I don't know
how to tell other people how to write shorter code. My examples here are step by
step progress, and hopefully you can learn by example.
Many of you will look at the last four lines of the long solution and think they
"do nothing". Great, just writing `$longNames` is enough for PowerShell itself
to pull the items out of the array and write them to the output, and they will
end up on screen. It was going to do that anyway, there's no need for us to
explicitly write that:

$items = Get-ChildItem –Path 'C:\'
$longNames = @()
$items | ForEach-Object –Process {
    If ($_.Name.Length -gt 10)
    {
        $longNames += $_.Name
    }
}
$longNames

9 lines, 188 characters.
But it needs a bit more understanding of the language to know why writing a
variable name on its own does anything, and what it does. But that is a common
pattern for PowerShell users familiar with functions.
As well as offloading work onto the computer, we can offload work to the
programmer's brain – this code stores the directory listing in a variable named
`$items` and pulls it straight out again, a needless double step going A to B to
C. We can connect the listing output to the loop input with a pipe and skip
right from A to C, but then understanding the code requires that the programmer
is comfortable enough with the way the language works to follow A to C with
nothing in between to hold on to:

$longNames = @()
Get-ChildItem –Path 'C:\' | ForEach-Object –Process {
    If ($_.Name.Length -gt 10)
    {
        $longNames += $_.Name
    }
}
$longNames

8 lines, 171 characters.
That doesn't need more understanding - we already used the pipeline – but it's
my observation from code and questions on the internet that this change is hard
for people. This changes the nature of the program from "taking clear, distinct
steps, one at a time" to "a flow from start to finish, however far it goes, all
at once". Knowing that pipelining things is possible doesn't seem to be enough -
it needs quite a lot of practice for this "let the data slide through"
code-shape to become comfortable and familiar.
The same thing happens from here on down – more understanding means greater
leaps. A to C becomes A to E, then A to J. The heart of all "code readability"
arguments might be whether the reader has enough familiarity of the patterns
used in the code, rather than whether the code itself is "readable", too long,
or too short.
From here, part of me wants to squash the `if` into a single line, part of me
wants to get rid of the `@() / +=` combination and have loop output to array in
one go – that's an example of what I was just writing, sending loop output into
a variable without any intermediate steps is a pattern that looks weird from
other languages, but gets more familiar with use - and part of me wants to get
rid of the separation of "storing the names, then displaying them" by merging
that into one "find and display them" step:

$longNames = Get-ChildItem –Path 'C:\' | ForEach-Object –Process {
    If ($_.Name.Length -gt 10) { $_.Name }
}
$longNames

4 lines, 129 characters.
This uses the same understanding from earlier ("why $longNames does something
when written on its own") to understand how writing `$_.Name` does something on
its own, even though the context is different. From directory listing to
variable, no stops along the way. A to D.
Have you noticed these changes work on different layers of the code? Some of
them are purely visual – removing line breaks from the `if` made no difference
to the way the code works. Others change what's happening behind the scenes -
connecting `Get-ChildItem` to `ForEach-Object` removed an array and a variable
name, uses less memory, without affecting the output. That's something else I
like – shortening the code involves understanding up and down the layers, from
PS reading the code, to what it does behind the scenes, to how those parts
interact with each other, to what exactly needs to happen to the data to solve
the problem.
If we can remove newlines around the `if`, let's do that a bit more and put
`$longName` up on the previous line, with the rest of the code:

$longNames = Get-ChildItem –Path 'C:\' | ForEach-Object –Process {
    If ($_.Name.Length -gt 10) { $_.Name }
} $longNames

Oh no!


ForEach-Object : Cannot bind parameter 'RemainingScripts'

Nothing happened when I took the newlines away from the `if` statement , but
take this one away and it won't run. This specific problem plagued me for a
while with short code challenges, and following up on that error and why it
happens was interesting and useful. Something else I'm not showing in this
article is how many times I try things which don't work. We'll undo that change,
and let's get rid of the names array instead, and output directly:

Get-ChildItem –Path 'C:\' | ForEach-Object –Process {
If ($_.Name.Length -gt 10) { $_.Name }
}

3 lines, 98 characters.
Some of you have been hitting your heads on why I'm using a loop and a test,
instead of merging them together and using `Where-Object` - why two steps
instead of one?? OK let's merge those:

Get-ChildItem –Path 'C:\' | Where-Object –FilterScript { 
    $_.Name.Length -gt 10
} | ForEach-Object -Process {
    $_.Name
}

5 lines, 136 characters. Longer.
I joke, you probably expected this shape:

Get-ChildItem –Path 'C:\' |Where-Object {$_.Name.Length -gt 10} |Select-Object -ExpandProperty Name

1 line, 99 characters (yay! Dropping below a 100 char cutoff is pleasing)
This is another dimension of it – my early changes made it shorter, no question.
But we're now at the point where some changes to make things shorter don't quite
do the same thing, and so they need another change elsewhere to compensate, and
the whole thing ends up longer. Squashing things into a small space is easy at
first, but after a while every push in one place makes things pop up somewhere
else, progress slows down, and that's a hint that you're getting past the easy
gains. Maybe it's a good place to stop?
I had to do something, the `if` test wasn't just checking the length it was also
extracting the `.Name` property. `Where-Object` can only do the length test, so
the Name property needs to be handled in new code. That's another dimension,
going from "script" to "oneliner" towards "codegolf" means testing the rules of
what's allowed as output. If the full directory listing output is OK, then we
can cut the entire last chunk from this code, if it's mandatory to just output
the names then we have to get the Name out. (Tip: argue with whoever set the
puzzle that your rule-bending output should be valid ;-))
And the shape of the code changed by merging the loop with the `if` test – it
now uses `Select-Object`. Writing short code requires knowing several different
ways to do things, so practicing writing code in different ways means you can
"choose the shortest way you can think of" compared to people who only know one
way.
Back to my original nitpick right up at the top, I'm going to call that last
example a oneliner: there's no variables, no loops, just three pipeline blocks
neatly connected, one each for the three stages of the problem – get data,
process it, output it. No stops. It's 8% of the lines and 40% of the typing, and
does the same thing.
Let's not end here, let's start here – assuming I still didn't want to type all
that at the console, let's go through the same tricks again:
1) Offload work to the computer
2) Offload work to the programmer
3) Use greater understanding of the language to do (1) and (2)
That means:
• `-ExpandProperty` - parameter can be shortened; if PowerShell can match what
you type to a single parameter, it will. Tiny bit of language knowledge, quite
common.
• Aliases: `where` and `select`, very common knowledge.
• Default parameters: with `Get-ChildItem` `-Path` is assumed for the first
parameter, if you don't type it. So commonly used, I used it all the time before
I even knew that's what was happening. Don't tell the computer to go that way,
if it was going that way anyway.
Now:

Get-ChildItem 'C:\' |Where {$_.Name.Length -gt 10} |Select –Expand Name

71 characters.
We just knocked a quarter of it off, and it's still almost the same. I'm happy
this is the kind of code I'd write at the command line, off the top of my head,
share with people, but not use in production scripts.
Repeat: same again – make the computer do work, use greater knowledge of the
language, etc. etc.
• Aliases: `?` and `gci`, quite common.
• In parameter parsing mode strings without spaces don't need quotes, again
common.
• `-Exp` is still unique, instead of `-Expand`, also common.
These changes make it:

gci c:\ |? {$_.Name.Length -gt 10} |select -exp Name

52 characters.
Another 30% reduction. Looking like a traditional "oneliner" now, getting
unreadable, approaching "codegolf" territory. There isn't a distinct cutoff that
I know of, but you can see it's nothing like the earlier code, and yet you
followed the blog post down this far step by step and you can also see it's
exactly like the earlier code.
Code so far has enough whitespace to be clear and readable, but "shortest code"
means delete all the spaces. The space between `c:\ |` can go and everything
will work. Remove the space between `gci c:\` and it won't work. Removing the
space from `} |select` is fine, removing the space from `-exp Name` isn't.
Trying these will give you errors, and exploring why the errors are coming
involves learning something about PowerShell.
Now we're at the point where there's a couple of spaces I could trim to drop
just below 50 chars, but that must be almost as far as it goes, right? We list
the directory contents, check the name length, expand the property. What else is
there to get rid of?
How far can it go? This is where it gets fun and challenging.

# remove the easy spaces, and gci has an alias 'ls' for –4 chars
ls c:\|?{$_.Name.Length -gt 10}|select -Exp Name    #48 chars

# select can take a pattern for the name as long as it's unique -2
ls c:\|?{$_.Name.Length -gt 10}|select -Exp N*    #46 chars

# comparisons and other operators don't always need spaces -2
ls c:\|?{$_.Name.Length-gt10}|select -Exp N*    #44 chars

# If you know how PowerShell handles properties on Arrays, rewrite for –8
(ls c:\|?{$_.Name.Length-gt10}).Name    # 36 chars

# Or, ForEach-Object can expand a property, a little known feature, -2
ls c:\|?{$_.Name.Length-gt10}|% N*     #34 chars

35% gone. And we dropped below three blocks, momentarily, with a big rewrite –
after going towards wildcard patterns, changing to a parentheses wrapper and
back to the full `.Name` still saved a lot. Come on brain, what else can we dig
up? TYPES! I haven't mentioned casting yet, and that is a huge part of it. Look
at this:

gci c:\ | ForEach-Object { $_ }     # directory listing output
gci c:\ | ForEach-Object { "$_" }    # names only !

If you force the output items to be a string, they become just the name, not the
whole directory listing, or the full path. For this problem, that's convenient.
For others, it isn't. In other code, casting between types is incredibly common
and tricks to cast between arrays, strings, numbers, are very useful. Let's
abuse the string cast and get rid of calling `.Name` entirely:

# Now $_ is a string name
ls c:\|%{"$_"}|?{$_.Length-gt10}    # 32 chars

# but wait, there's a trick with `Where-Object` to avoid the scriptblock
# we couldn't use it for a double lookup Name.Length but now 
# we have unlocked it, because we're working with one property, -2
ls c:\|%{"$_"}|? Length -gt 10    # 30 chars

# and that trick can take patterns for the property name, -3
ls c:\|%{"$_"}|? Le* -gt 10    # 27 chars

What else do I happen to know about strings, casting, types, pattern matching?
Regular Expressions! I skip over another pile of background knowledge and edge
case behavior, and show:

# Completely different array filtering approach, based on using a regular expression to count
(ls c:\)-match'.{10,}'|%{"$_"}    # 30 chars (boo)

# use a previous short version of `%` again, -3
# "going back to something I was using" happens a lot
(ls c:\|% n*)-match'.{10,}'    # 27 chars (Q: why are the parens needed?)

Wait. This is getting silly. Almost halved the 52. And if you just saw one of
these answers pasted into a web page, you wouldn't see the pages of "getting it
a bit shorter each time" happening earlier. It would look like "What, who can
just write that, one-liners are awful".
Anyway, I try a lot of things. I spend a lot of time on it. I drag in as much
knowledge as I can find, all that matters is getting the right output. It's a
form of minimalism, if you can scrape by with a skeleton crew of code and pieces
falling off everywhere, as long as it gets past the finish line once, everything
else can go. At the same time, it's not minimalism – if you can spend 1GB of
memory and 5 seconds of timewasting to save 1 character, do it and be grateful
for it.
Two completely different approaches, both hitting 27 characters.
This fascinates me; the early code and the tiny code are so different to humans,
but do the same thing.
This

$longNames = @()
Get-ChildItem –Path 'C:\' |
ForEach-Object –Process {
    If ($_.Name.Length -gt 10)
    {
        $longNames += $_.Name
    }
}
$longNames

Is the same as this


ls c:\|%{"$_"}|? Le* -gt 10

and this


(ls c:\|% n*)-match'.{10,}'

People find one more readable, more writable, but the computer is never
confused. This makes me feel there's something really interesting underneath
this about "expressing computation". How can they be so different and "do the
same"? How much of the code is important, how much is fluff? What features could
this language be missing that could make that computation shorter or clearer?
Is that is? Can it go below 27 characters? (hint: yes, I have a 25 .. so far)
One last tip for those willing to compete in codegolf competitions: spend a lot
of time on them, and then present them as a finished script that looks
effortless. And practice rewriting and rewriting in different ways. And
shamelessly steal every code-shortening idea from other people that you can
possibly find, put them ALL in.


2. Tell us a bit about yourself and about the way you got to PowerShell.


I have a long dislike of writing code as an amateur and sharing it with people,
only for them to say "I haven't got Python, or a Java runtime" or "how do I
install that" or "what's the Visual Basic runtime?". I envied the Linux
distributions with their built-in C compilers and Perl and Python, almost as
much as I didn't enjoy VBScript.
When PowerShell came to Windows I jumped on it. Windows Vista, PowerShell 1 or
2. At last a powerful scripting language everyone would have by default!
I didn't understand it, and I dropped it.
A few years later, 2012 ish, working in IT with Exchange requiring it, newer
versions getting better and better, it grew on me. Then it took over from Python
as my everyday playing around language, now I'm a J. Snover's Witness.



3. Can you tell us your approach to Task 1?

Task 1 mandated the use of `Win32_Share` and the shortest way I know is with
`gwmi`. After a few trials and errors, I thought of the forced-cast-to-string
approach mentioned above and checked to see what happens - one output object
becomes:

\\Computer01\root\cimv2:Win32_Share.Name="ADMIN$"

That's so close to the required output format, string cutting to get rid of the
middle bit has got to be one of the shortest possible routes to an answer. And
trim the annoying trailing quote. Luckily I like Regular Expressions, so a bit
of `-replace` experiments later and I have something that seems roughly as good
as I could ever get it.


4. How did you cope with Task 2?

I stared at it, and I saw it needed `$question` to be used and print this
output:

The B in Benoit B. Mandelbrot stands for Benoit B. Mandelbrot.

The words "in, stands, for" are not in $question so they must be in my code.
"Benoit B. Mandelbvrot" is in the answer twice, remove that duplication, fin.
In my head was the shape "output string, get the first `Benoit B. Mandelbrot`
from `$question` with string manipulation (== probably regex), use it and store
and re-use for the second place it appears, probably in a sub-expression in the
string".
And then trial and error until I had it quite short. As it happened, SubString
came out shorter than regex. This rarely happens. The most pleasing adjustment
in my answer was taking the space in front of `Benoit` from the input as well.


5. Your oneliner for Cosine Similarity is impressive. Can you explain how you
got to such a short solution?

Nope ?? The whole of this article is trying to answer this question. All that –
trial and error, codegolf experience, weird language behavior edge cases,
looking at the language specification, spending lots of time, knowing a pile of
short-code tricks – that's how.
This one was scary. I hadn't heard of it before, I'm not a skilled
mathematician, and the Wikipedia page math-terminology-explanation was no help.
It took me quite a while of Googling before I decided to look at the Reddit
discussion, expecting other people to have finished it already. Other people
were puzzled and that was a bit of a relief.
After finding C# examples, explanations, discussions, I started to get a clue.
It's word counting, adding, dividing, then I could start to make sense of the
Wikipedia equation – A1*B1 + A2*B2 … An*Bn on the top. A1 squared + A2 squared …
An squared on the bottom left. Same for B on the bottom right. I can make those
work.
Something which isn't covered in the previous few pages, is the way I split it
into smaller parts – lots of testing how to split the input strings into words,
lots of testing ways of counting words in sentence 1 vs sentence 2, before I
started combining the code together and trying for a full answer. Then a lot of
struggling to get past the "no semi-colons" restriction.
Particular techniques in this answer:

$a=1   # assign a variable
($a=1)  # assign variable, and use value 1 right here in the code as well

foreach () { } $t    # because, as noted earlier
... | Foreach-object { } $t    # this structure doesn't work

Instead of writing these:


$lowerLeft += $a * $a
$lowerRight += $b * $b

with a semicolon:


$lowerLeft += $a * $a; $lowerRight += $b * $b

It was a moment of insight to use:


$throwawayVar = ($lowerLeft += $a * $a), ($lowerRight += $b * $b)

Programming by side effect, making an array of the results and ignoring it. It
still looks like a very redundant answer to me, three big repeating patterns, I
was expecting someone else to get rid of them and be 1/3rd shorter.
It was only by coding it that I came to understand what it did, and spent a
while pacing up and down explaining to myself what an N-dimensional cosine
means, why it makes any sense at all relating to documents and words, how it
measures document similarity, and imagining dogs pulling in the 'bacon'
direction vs the 'dog park' direction. So that was fun.

TL:DR:

One dimension:

0 --- 1 --- 2 --- 3 --- 4 --- > Bacon.


A dog which pulls strength 3 in the bacon direction is similar to another dog
which pulls strength 3 in the bacon direction. They are different from a dog
which pulls strength 1 in the bacon direction.
A document which says "bacon bacon bacon" is similar to another "bacon bacon
bacon", but they are different from "bacon".

Two dimensions:

/\ Dog Park (up)
|
0 --- -> Bacon (right)


Dogs which pull strongly towards bacon are similar. Dogs which pull in both
directions equally, can't make up their minds, and go off at an angle – are
similar. Dogs pulling in the Dog park dimension are similar.
Dogs pulling towards bacon are a bit different from dogs pulling in both
directions and going at an angle.
Dogs pulling towards bacon only are very different from dogs which pull towards
dog park only.


Exactly how strongly they pull in each direction, determines which angle they go
off at, mostly bacon, mostly dog park, or split the difference.
A document which says "bacon bacon park park bacon park" is similar to "park
park park bacon bacon bacon". It pulls in both dimensions and goes off at an
angle. It's a bit different from "bacon park park park" which pulls more towards
the park. It's very different from "park park park park park" which pulls only
towards the park.
Each word is a direction, a dimension. The word count is how strongly the
document "pulls" in that direction. After all the pulls combine, the document
goes off at an angle. Different word counts make different angles. This equation
works out "how different". I can't visualize more than 3 dimensions, but I can
up to 3 and it now makes sense that it works. More words, more dimensions, same
idea.



6. What's your take on Powershell for one-liners if compared to other languages
you might know?

For shell use oneliners, there isn't any other language quite in the same
category so it's great. For general purpose programming one-liners I like it,
plenty of convenience syntaxes. Some things that annoy me. I tend to forget it's
an admin scripting language, and instead wish it pulled in every convenience
feature from every language I'm dimly aware of.
http://codegolf.stackexchange.com is a multi-language site, and in my experience
the answers (other people's answers, I don't know most of the languages!)
separate themselves into tiers:
• Really short: single-purpose languages designed for golfing – GolfScript,
CJam, many others.
• Short: the major scripting languages - Perl, Python, JavaScript, PowerShell,
Ruby, etc.
• Medium: mainstream languages, older languages with fewer built-in conveniences
(C#, Java, Lisps)
• Long: novelty answers - SQL, etc.
PowerShell has a reputation for being long and wordy, but the language designers
did a fantastic job with the "elastic syntax" to make those things optional, and
with things like automatic module imports and type accelerators, being a shell
and having direct access to the filesystem it is strong. Other languages save
not needing `$` on variable names, but then can't put variables in strings
easily. Or they have better string slicing but worse regex subroutines.
PowerShell tends to be slightly behind the other popular languages, often
because you need quotes and parens so much or don't have quite as easy
int->char->string conversion.
What really seems to make the difference is whether language X happens to have a
convenience feature that fits the question. Often the languages trade places for
different problems, so JavaScript might have a short way of doing one thing, but
C# has a lambda expression and Linq combo which surpasses it for other things,
and Mathematica has an inbuilt list of country names so it takes a winning place
in some specific question, etc. PowerShell is fun, competitive enough.



Publié par Carlo à l'adresse 7:06 AM 14 commentaires
Email ThisBlogThis!Share to TwitterShare to FacebookShare to Pinterest
Libellés : poshcontest2017, powershell

Older Posts Home

Subscribe to: Posts (Atom)


 * About Me
 * JAPE Hall of Fame
 * Microsoft Update Tuesday


Web Toolbar by Wibiya




POWERSHELL MVP






Follow @sysadm2010



BLOGS I LIKE TO READ...

 * vInfrastructure Blog
   Issue during the upgrade of a VMware Horizon Connection Server - Reading
   Time: 2 minutes The Connection Server is the main component of a VMware
   Horizon infrastructure. But usually for a redoundancy and performance pro...
   1 week ago
   
 * The Lonely Administrator
   Using PowerShell Your Way - I’ve often told people that I spend my day in a
   PowerShell prompt. I run almost my entire day with PowerShell. I’ve shared
   many of the tools I use daily on...
   4 weeks ago
   
 * Blog O' Matty
   Using terrascan to detect compliance and security violations - Over the past
   several years I’ve read numerous horror stories about cloud deployments gone
   wrong. S3 buckets with PCI data left open to the raw Internet, E...
   1 month ago
   
 * Jonathan Medd's Blog
   Automating SonarCloud with PowerShell – Part 3 Onboarding a User - Warning:
   this post contains unsupported API calls, so use at your own risk Similar to
   the situation in Part 2 for onboarding a project into SonarCloud, onb...
   6 months ago
   
 * Power The ShellPower The Shell
   How to run kubeflow on AKS - What’s Kubeflow ? Let me copy/paster two lines
   from wikipedia : At its core, Kubeflow offers an end-to-end ML stack
   orchestration toolkit to build on Kuber...
   6 months ago
   
 * Mike F Robbins
   Moving my Enterprise Grade Network Equipment to a New Home - My family has
   been out of town this week. Light bulb moment! It’s the perfect time to cut
   holes in sheetrock and drill holes in ceilings to install my home...
   1 year ago
   
 * Last In - First Out
   Building Non-Functional Requirements Framework - Requirements Categories -
   *I'm planning on documenting a framework that we built for managing
   non-functional requirements. This is post #2 of the series.* In Post #1, Last
   In - F...
   1 year ago
   
 * LucD notes
   A Hitchhikers Guide to SRS 1.0.0 - Sometimes announcements tend to disappear
   in the cracks of time. When the Script […]
   1 year ago
   
 * LazyWinAdmin
   Terraform - Uploading a local PowerShell module to an Azure Automation
   account - This article demonstrates how to use Terraform to upload a local
   PowerShell module to an Azure Storage Account and importing it to an
   Automation Account us...
   1 year ago
   
 * Rohn's Blog
   You Can Automate 100% of Your Compliance Checks - Intro It’s me again. It
   looks like it’s been over 3 years since I’ve made a blog post (wow, time
   flies!). First of all, I’m sorry about that. I don’t know...
   1 year ago
   
 * IT Cold cup of coffee
   3333 -
   2 years ago
   
 * Richard Siddaway's Blog
   Time for cube calculation - My recent post on spheres got me wondering about
   the time for cube calculation. Defining a variable PS> $r = 2.37 I can
   calculate the cube by multiplying $...
   2 years ago
   
 * The Life of a Sysadmin
   QRP weekend - This weekend has been 2/3 good for radio.
   3 years ago
   
 * The Lone SysAdmin
   Building a statically linked rsync - Install dependencies for building: yum
   -y install glibc-static popt-devel popt-static Download, then build: tar xf
   rsync-3.0.9.tar.gz cd rsync-3.0.9 ./co...
   3 years ago
   
 * JasonHelmick
   Pluralsight IPO – PS -
   4 years ago
   
 * Learn Powershell
   Quick Hits: Getting the Local Computer Name - I’ve had a few emails and
   questions about the best way to get the hostname of the local computer that
   you are currently logged into and felt that a quick (...
   4 years ago
   
 * IT Pro PowerShell experience
   PSConfEU – lessons learned - [image: Question - Ewa Bielawska, 3]PowerShell
   Conference Europe was closed more than a month ago, but that time was filled
   with the content from that co...
   5 years ago
   
 * About Roy
   Vikash Kumar Roy Resume - Seven years back I posted this blog . Now it is
   time to move forward and explore new opportunities. I am all set with my new
   resume. Let me know if you hav...
   5 years ago
   
 * Standalone Sysadmin
   Debian Jessie Preseed – Yes, please - What could possibly draw me out of
   blogging dormancy? %!@^ing Debian, that’s what. I’m working on getting a
   Packer job going so I can make an updated Vagra...
   6 years ago
   
 * Jeremy Waldrop's Blog
   UCS VIC 1340/1380 PCI Placement - I recently did a UCS implementation that
   included the B460-M4 blades. If you aren’t familiar with these beasts you
   should look them up. They are two B260 f...
   6 years ago
   
 * David Ball Blog
   The X Factor: International Pop Singer Competition - *The X Factor* is a
   television music competition franchise created by Simon Cowell. It originated
   in the United Kingdom, where it was devised as a replacem...
   7 years ago
   
 * My SysAd Blog -- Unix
   Make sure you typed the name correctly, and then try again error message -
   Sometimes the Windows uninstall program leaves orphan files after a removal
   event. Here were the error messages and some background information.
   http://www...
   8 years ago
   
 * Jeff Hengesbach
   Error 0x800F0A12 Installing SP1 on Windows 2008 R2 Veeam System - I ran into
   a little issue trying to update my Windows 2008 R2 system that serves as my
   Veeam Backup server. It did not matter whether I tried the SP1 inst...
   10 years ago
   
 * Tobias Weltner's blog
   -
   
   
 * Site Home
   -
   
   


 * Regex101
 * Syntax Highlighter
 * Windows Memory
 * WSS 3.0 Insight
 * Powershell Code




LINUX DISTRO I LIKE

 * CentOS
 * Gentoo Linux
 * Linux Mint
 * The FreeBSD Project
 * The Slackware Linux Project




BLOG ARCHIVE

 * ▼  2019 (1)
   * ▼  January (1)
     * Artificial Neural Networks in PowerShell - part 1

 * ►  2018 (6)
   * ►  July (1)
   * ►  June (3)
   * ►  February (2)

 * ►  2017 (19)
   * ►  December (3)
   * ►  November (4)
   * ►  June (2)
   * ►  March (2)
   * ►  February (3)
   * ►  January (5)

 * ►  2016 (26)
   * ►  December (2)
   * ►  November (5)
   * ►  October (6)
   * ►  August (1)
   * ►  July (2)
   * ►  June (4)
   * ►  May (2)
   * ►  April (3)
   * ►  March (1)

 * ►  2015 (19)
   * ►  December (5)
   * ►  November (1)
   * ►  October (3)
   * ►  September (1)
   * ►  July (1)
   * ►  June (3)
   * ►  May (3)
   * ►  April (1)
   * ►  February (1)

 * ►  2014 (19)
   * ►  December (2)
   * ►  November (5)
   * ►  October (2)
   * ►  August (1)
   * ►  July (3)
   * ►  June (1)
   * ►  February (1)
   * ►  January (4)

 * ►  2013 (49)
   * ►  December (5)
   * ►  November (8)
   * ►  October (2)
   * ►  September (1)
   * ►  August (1)
   * ►  July (3)
   * ►  June (5)
   * ►  May (2)
   * ►  April (6)
   * ►  March (3)
   * ►  February (8)
   * ►  January (5)

 * ►  2012 (64)
   * ►  December (7)
   * ►  November (2)
   * ►  October (8)
   * ►  September (10)
   * ►  August (3)
   * ►  July (9)
   * ►  June (9)
   * ►  May (3)
   * ►  April (6)
   * ►  March (2)
   * ►  February (3)
   * ►  January (2)

 * ►  2011 (43)
   * ►  December (4)
   * ►  November (5)
   * ►  October (1)
   * ►  July (1)
   * ►  June (7)
   * ►  May (5)
   * ►  April (1)
   * ►  March (6)
   * ►  February (6)
   * ►  January (7)

 * ►  2010 (85)
   * ►  December (6)
   * ►  November (19)
   * ►  October (14)
   * ►  September (3)
   * ►  August (26)
   * ►  July (17)




SUBSCRIBE TO

Posts
Atom

Posts

All Comments
Atom

All Comments





LABELS

powershell windows vmware windows 2008 R2 microsoft esx vsphere linux windows
2012 esxi windows 2008 error intel scripting windows 2003 windows 7 scripting
games scvmm lab ntfs dfsr hyper-v wmi DNS NetApp active directory docker hp
performance ssd antivirus iops mvpbuzz powercli registry unix windows 2003 R2
windows 2016 windows 8 IIS PSDSC SAN dhcp diskspd dotnet firewall msdos mvp nas
poshcontest2017 refs sharepoint storage wss wsus BIOS SATA batch cloud cluster
cpu architecture deduplication owncloud r2 regex security service pack ssh trend
uac webdav windows vista winsxs Crucial azure containers dfsn eventlog hardware
iSCSI kms licensing mcafee netstat networking newsid oneliner perfmon php
pshgames robocopy server slmgr ssl starwind symantec backup exec symantec
endpoint 11 sysprep twitter usb vmotion vsphere 5.1 windows XP winrm NanoServer
acl amd array bash blogging certification china cmdlet database dfs disk space
issue dynamic memory ethernet fileacl filer files iaas internet ise it joke
master file table mysql nand netsh nfs poshcontest2015 poshcontest2016
powershell4 proxy psexec rdp resilient file system samsung slsvc solid state
drive sql sql server svchost.exe trim troubleshooting tutorial unicode vcp vcp5
vdr virtualisation vmdk vmfs vmware certified professional vsphere update
manager webclient wind windows 8.1 windows update 0x800706BE 10016 2010 2381
74-409 API DCOM DDR3 DEP DfsDnsConfig EPT EVC FSMO FTP G.Skill GPO HTPC IAS LEAN
MSI PSU Pester Referral Cache TPS TSM UEFI VSS Win32 aam access denied
activeperl admin tools administrator admx adsense ahci alldocs alternate data
streams arduino audit authentication auto-logon backup baidu beta bitwise blade
blogger blogspot books boot boot time breaking news bsod bug bugcheck bz2 cURL
centos cifs cisco citrix clip comparison compatibility computer conhost contest
convertfrom-string copy-item core cores corsair csrss debian dfsutil dhcpd
diagnose diagnostic dimm dism; disk space issue download driver dropbox dsget
dsquery dump e-book ebook edit emc encryption errror ethtool etw exam excel
executionpolicy facebook feedburner filesize flr folders fprpc freesshd freeze
fun funny get-computerinfo get-content gigabit github google google+ green
computing group policy hashing hashtable history hotfix hponcfg https iconv ide
ie 8 ifcfg-eth0 iis 7.5 ilo image2docker installation internet explorer 8
internet explorer 9 ipad ipconfig ipv6 ivy bridge jagged arrays jape javascript
kde kinect kixtart.org latin1 license link exchange linkbucks linux mint 11 lock
locked file logfiles logman mbr memory memtest86+ metaframe mft modulo money
monitoring moss mup.sys mvpsummit mysqld ncq netbios netrfileclose neural
network neuron nic nmap oneget openfiler openssh operating systems overclock
overvolt ownership p2v pace-band perl picoPSU ping pint pinvoke plink poshrsjob
powershell v4 powershell v5 powershellget price prime procmon programming psfile
psobject psreadline putty puzzle pxe query rack raid ram rar readlines regedit
remote administration remotefx rename report reram ris rpc runners sandy bridge
search engine serverprotect service control manager shadows copy shareponit sid
silent single sign-on slat social media special characters splatting sql server
management srvs sso startup steve ballmer sudo summit svga syntax sysinternals
syslinux tablet tagging task scheduler tcpdump test-connection tftpboot thin
provisioning tips tomcat top500 touch treesize trunking tsql ttl tweaks ubuntu
unattended underclock undervolt unrar upgrade usa utf-16 utf-8 vcenter vcloud
vcloud connector veeam vlan vmkfstools vmware tools vmware workstation
vmworld2013 waik wattmeter wds weather windbg windord windows 2000 windows 2012
R2 windows NT wmic workflow workflows xen server xinorbis xml



POPULAR POSTS

 * QWINSTA and RWINSTA
   If you need to RDP a remote Windows server and all the sessions seem to be
   unavailable, you may use two utilities to kill offending/exceed...
   
 * Reading large text files with Powershell
   Any sysadmin out there knows that log files are an invaluable asset for
   troubleshooting issues on their servers. Sometimes though these kin...
   
 * The disk is offline because of policy set by an administrator
   You have just installed or cloned a VM with Windows 2008 Enterprise or
   Datacenter or you have upgraded the VM to Virtual Hardware 7 and un...
   
 * Understanding Windows Services Recovery features
   As you probably know Windows has the ability to automatically perform some
   predefined action in response to the failure of a Windows Servic...
   
 * How to register a vCenter Server with a Web Client
   Today I want to write a post explaining how to solve a recurring problem when
   trying to access the vSphere Web Client for the first time i...
   
 * Multidimensional arrays in Powershell
   Today I want to talk a little about multidimensional arrays in Windows
   Powershell . Multidimensional arrays are one of the complex data typ...
   
 * Powershell Oneliner Contest 2015 - Win a Hyper-V book
   I have always enjoyed taking part in most of the Powershell contests out
   there since Powershell is kind of a recreational administration l...
   
 * Powershell gymnastics - Prime numbers
   Some days have passed since the last time we did gym and by now you should be
   properly rested and ready for another Powershell workout. T...
   
 * Real world data deduplication savings under WIndows 2012
   I have been testing Windows 2012 Data Deduplication for quite a long time now
   ( starting from last October when I wrote for the first time...
   
 * WSUS management with PowerShell
   I have recently discovered the work of fellow MVP Adam Marshall  who wrote a
   fantastic script aimed at cleaning your WSUS servers and deci...
   




FOLLOWERS





Stats








ANIMATOR

↑ Grab this Headline Animator


Worth



Picture Window theme. Powered by Blogger.