Powershell code help

What's Hot
Emp_FabEmp_Fab Frets: 24302
I've never tried writing Powershell so I'm clueless as to the syntax.

I have a line of code that generates a random 8 digit integer.  What I need is some more code to test whether this integer contains any duplicate adjacent numbers, such as 92257032 or any sequential ascending adjacent numbers, such as 73978025 and, if either of these conditions are true then go back to the line that generates the random number and do it again.

Is this an easy bit of code for anyone to write please ?

Ta Muchly !
Lack of planning on your part does not constitute an emergency on mine.
Also chips are "Plant-based" no matter how you cook them.
0reaction image LOL 0reaction image Wow! 0reaction image Wisdom
«1

Comments

  • I'm not sure about powershell, but assuming you can do for loops, and have some sort of goto (which usually isn't a good idea but isn't too bad if you are careful). 

    The basic approach would be:

    Loop i from 0 to length of the number - 1 
    At every iteration check the digit at i and at i+1, if they are the same or consecutive then go back to the start

    To get the individual numbers you can do something like 

    digit = number/(10^i) % 10. 


    0reaction image LOL 0reaction image Wow! 0reaction image Wisdom
  • notanonnotanon Frets: 607
    edited November 2019
    I'm on a mobile at the moment but if you search for:

    regular expression adjacent duplicate characters

    You should find a jsfiddle example. Then it is easy to convert a number to string and vice versa finally using a regex to check in powershell is easy.

    0reaction image LOL 0reaction image Wow! 1reaction image Wisdom
  • randellarandella Frets: 4168
    notanon said:

    regular expression adjacent duplicate characters


    My career in programming:

    “One of these days I’m going to properly learn Regex.”

    *Googles pre-prepared pattern*

    ”Yep, one day I’m going to properly learn Regex.”
    0reaction image LOL 0reaction image Wow! 0reaction image Wisdom
  • Emp_FabEmp_Fab Frets: 24302
    I know what pseudo-code I need, I just don't know the powershell syntax.

    Basically, it's going to be;

    Generate Random Number
    Convert integer to string
    for character n in string
       if (value of character n = value of character n+1) OR  (value of character n - value of character n+1 = -1) then go to Generate Random Number

    That's it.

    I just don't know any powershell syntax !
    Lack of planning on your part does not constitute an emergency on mine.
    Also chips are "Plant-based" no matter how you cook them.
    0reaction image LOL 0reaction image Wow! 0reaction image Wisdom
  • There's a good regex tester somewhere on the internet.
    Some folks like water, some folks like wine.
    My feedback thread is here.
    0reaction image LOL 0reaction image Wow! 0reaction image Wisdom
  • I am not a Powershell coder, but I've chucked this together which is 95% there I reckon.

    $output = ""
    
    
    while ($output -eq "")
    {
        $input = Get-Random -Maximum 9999999 -Minimum 10000000
        $inputAsCharArray = $input.ToString().ToCharArray()
    
        $valid = $True
    
        for (($i = 0); $i -lt $inputAsCharArray.Count; $i++)
        {
          If ($inputAsCharArray[$i] -eq $inputAsCharArray[$i+1] -or $inputAsCharArray[$i] -eq $inputAsCharArray[$i+1] - 1)
          {
            $valid = $False
          }
        }
    
        If ($valid -eq $True)
        {
            $output = $input
        }
    }
    
    Write-Host $output
    0reaction image LOL 0reaction image Wow! 0reaction image Wisdom
  • notanonnotanon Frets: 607
    edited November 2019
    Sorry I got mixed up with checking which regex is good at. To generate, if you are 'old school' then this should make sense:
     
    Function GenerateRandomIntegerString([Int] $InLength){
    
        [String] $CurrChar = ""
    [String] $LastChar = "x" # cannot equal $CurrChar
    [String] $FullString= "" While ($FullString.Length -lt $InLength)
    {
    $CurrChar = (Get-Random -Maximum 9 -Minimum 0).ToString()
    if ($CurrChar -ne $LastChar){
    $FullString = $FullString + $CurrChar
    $LastChar = $CurrChar
    }
    } return $FullString } $MyVar = GenerateRandomIntegerString(7) # 8 'digits' required
    Write-Host $MyVar # Can also use VariableName.ToInt32() if a true Integer is required
    But I would recommend reading about Powershell Functions: https://4sysops.com/archives/the-powershell-function-parameters-data-types-return-values/ Rather than generate all the string then check for duplicates on the previous, should be less attempts to get a unique number? Should be fine.
    0reaction image LOL 0reaction image Wow! 0reaction image Wisdom
  • notanonnotanon Frets: 607
    edited November 2019
    A better version which disallows leading 'zeros' and uses a more powershell function syntax is below, I would not use this in production unless checked. Maybe run it a few thousand times or await code review from fellow tFB folk.

     Function GenerateRandomIntegerString{
    
    #Generates a string of numbers that do not contain duplicate adjacent numbers such as:
    # 777766 will fail due to a duplcate 7 (3 duplicates) also there are duplicate 6s.
    # Second parameter determines if a leading zero is allowed.
    
    param(
        [Int] $InLength,
        [Bool] $LeadingZero
        )
    
    
        [String] $CurrChar = ""
        [String] $LastChar = "x" # cannot equal $CurrChar  
        [String] $FullString= ""
    
        While ($FullString.Length -lt $InLength)
        {
            $CurrChar = (Get-Random -Maximum 9 -Minimum 0).ToString()
            if ($CurrChar -ne $LastChar){ 
                    $FullString = $FullString + $CurrChar
                    if (($LeadingZero -eq $False) -AND ($FullString.Length -eq 1 ) -AND ($CurrChar -eq "0"))  {
                    #Discard in this case
                         $FullString = ""
                    }
                    else {
                        $LastChar = $CurrChar
                    }
    
            }
        }
    
        return $FullString
    
    }
    
    $MyVar = GenerateRandomIntegerString -InLength 8 -LeadingZero $False
    Write-Host $MyVar
      
    0reaction image LOL 0reaction image Wow! 0reaction image Wisdom
  • @notanon beat me to it.  I was going to say that generating a random number, then going round a loop which filters out "bad" values, doesn't seem like the best approach.  A better solution would be to (as in @notanon's solutions) apply the constraints *while* generating the number.  This means the algorithm has a deterministic runtime.
    Trading feedback | FS: Nothing right now
    JM build | Pedalboard plans
    0reaction image LOL 0reaction image Wow! 0reaction image Wisdom
  • Emp_FabEmp_Fab Frets: 24302
    Thanks for that @notanon. ; However - it doesn't take into account the other requirement to not have consecutive ascending numbers - i.e. 23, 89, 56 and so on.  I'm not bothered about the code being elegant or following best practice - I just want it to work ! :lol: 
    Lack of planning on your part does not constitute an emergency on mine.
    Also chips are "Plant-based" no matter how you cook them.
    0reaction image LOL 0reaction image Wow! 0reaction image Wisdom
  • martmart Frets: 5205
    I have no idea about powershell, but I’d do this by generating a string of 8 random digits, with the first in the range 0..9 and all the following ones in the range 2...9.

    The first of these will be the first digit of your number. Then add this first digit to the second random number (modulo 10) to get a digit that is guaranteed to be different and non-sequential. This will be your second digit. Then add this to the third random number to get the next digit, and so on.

    Keep on like that through all 7 following digits and you’ll have an acceptable number. This involves no checking, only some additions, so may be quicker.
    0reaction image LOL 0reaction image Wow! 0reaction image Wisdom
  • oafoaf Frets: 300
    I know nothing about coding on Windows but I've come up with this and it appears to do what you want (it's a complete script save it as something.ps1 and then right click and "Run with PowerShell"). Windows then asks you some weird question about "Execution policy change" (as I say I know nothing about PowerShell or Windows programming...!) but answer Y and it will run.

    For ($i=0; $i -le 100; $i++) {
        $number = ( Get-Random -Minimum 10000000 -Maximum 99999999 ).ToString('00000000')
        if ($number -match '([0-9])\1{1}') {
            Write-Output "$number has adjacent digits"
        } else {
            Write-Output $number
        }
    }

    Read-Host -Prompt "Press Enter to exit"

    Example output:

    48149849
    88392049 has adjacent digits
    69629333 has adjacent digits
    93421931
    33938885 has adjacent digits
    27025547 has adjacent digits
    26200646 has adjacent digits
    30958706
    77199817 has adjacent digits
    83497267
    34300892 has adjacent digits
    22425763 has adjacent digits

    As notanon suggested regex are typically the way to go for this kind of thing.

    0reaction image LOL 0reaction image Wow! 0reaction image Wisdom
  • oafoaf Frets: 300
    ^ and I've deliberately not given you the entire answer but you can easily glue some logic in to fit :)
    0reaction image LOL 0reaction image Wow! 0reaction image Wisdom
  • notanonnotanon Frets: 607
    oaf said:
    ^ and I've deliberately not given you the entire answer but you can easily glue some logic in to fit :)
    As @djspecialist says there could be a huge number of miss his if you generate the number and then test rather than test as it is generated. That is why I ditched the regex approach.
    0reaction image LOL 0reaction image Wow! 0reaction image Wisdom
  • notanonnotanon Frets: 607
    Emp_Fab said:
    Thanks for that @notanon. ; However - it doesn't take into account the other requirement to not have consecutive ascending numbers - i.e. 23, 89, 56 and so on.  I'm not bothered about the code being elegant or following best practice - I just want it to work ! :lol: 
    Do you want me to modify the code or can you figure out out now? Use absolute value of the difference of the two numbers. Can I ask what this is for? I'm curious why you need these restrictions.

    Apologies for not reading the whole post, a bad habit of mine which is getting worse as I get older - frighteningly so.
    0reaction image LOL 0reaction image Wow! 0reaction image Wisdom
  • notanonnotanon Frets: 607
    I'm on a mobile at the moment but can take a look this evening.
    0reaction image LOL 0reaction image Wow! 0reaction image Wisdom
  • oafoaf Frets: 300
    Ha I didn't notice the sequential adjacent requirement either...! Easy to change the regex though :-)

    Tbh I'd be surprised if having to generate/test/regenerate caused a huge overhead/problem. If performance is important then I'm not sure PowerShell would be the first choice anyway!
    0reaction image LOL 0reaction image Wow! 0reaction image Wisdom
  • notanonnotanon Frets: 607
    edited November 2019
    @Emp_Fab ;;
    OK try this which only checks for ascending digits with a difference of 1. If you wanted a descending check then absolute value would be needed before the check -ne 1

    Function GenerateRandomIntegerString{
    
    #Generates a string of numbers that do not contain duplicate adjacent numbers such as:
    # 777766 will fail due to a duplcate 7 (3 duplicates) also there are duplicate 6s.
    # Second parameter determines if a leading zero is allowed also checks for ascending values.
    
    
    param(
        [Int] $InLength,
        [Bool] $LeadingZero
        )
    
    
        [String] $CurrChar = ""
        [String] $LastChar = "99" # cannot equal last char but must be numeric and greater than 10 to meet requirements
        [String] $FullString= ""
    
        While ($FullString.Length -lt $InLength)
        {
            $CurrChar = (Get-Random -Maximum 9 -Minimum 0).ToString()
            if (($CurrChar -ne $LastChar) -AND ( ([int]::Parse($CurrChar) - [int]::Parse($LastChar)) -ne 1))
            { 
                    $FullString = $FullString + $CurrChar
                    if (($LeadingZero -eq $False) -AND ($FullString.Length -eq 1 ) -AND ($CurrChar -eq "0"))  {
                    #Discard in this case
                         $FullString = ""
                    }
                    else {
                        $LastChar = $CurrChar
                    }
    
            }
        }
    
        return $FullString
    
    }
    
    $MyVar = GenerateRandomIntegerString -InLength 8 -LeadingZero $False
    Write-Host $MyVar
    
    
    
    0reaction image LOL 0reaction image Wow! 0reaction image Wisdom
  • Emp_FabEmp_Fab Frets: 24302
    edited November 2019
    @notanon ; - Thanks a million man.....  That's working perfectly !!!!  To answer your question, it's part of a larger script used for setting up new laptops.  This particular bit is for generating Bitlocker PINs.  Annoyingly, the domain Bitlocker policy is set to disallow PINs with consecutive matching or numerically ascending numbers.  I'm guessing it's intention is to stop people using "8888888" or "12345678" etc.  The existing script doesn't account for these restrictions and generates unusable PINs at least 70% of the time, meaning we have to restart the script until we get an acceptable one (which is a pain in the arse when you have a stack of laptops to sort).  Now I have your code, I can slot that into the existing script and it will all be smooth sailing !!

    Thanks again.  Very much appreciated !!
    Lack of planning on your part does not constitute an emergency on mine.
    Also chips are "Plant-based" no matter how you cook them.
    0reaction image LOL 0reaction image Wow! 0reaction image Wisdom
  • Emp_FabEmp_Fab Frets: 24302
    Actually, leading zeros are valid, so I can ditch the check in the middle.
    Lack of planning on your part does not constitute an emergency on mine.
    Also chips are "Plant-based" no matter how you cook them.
    0reaction image LOL 0reaction image Wow! 0reaction image Wisdom
Sign In or Register to comment.