Monthly Archive

Categories

Monthly Archives: November 2018

Test if string contains numeric

How can you test if a string contains a numeric character?

The simple answer is to use a regular expression. If you’ve been reading my stuff for any length of time you’ll know how much I love regular expressions. This is a simple regex.

Create a string

PS> $s1 = 'qwertyuiop'

Test if it has numerics

PS> $s1 -match '\d'
False

if you use D you’re testing for non numeric characters
PS> $s1 -match '\D'
True

 

Lets add a numeric to confirm

PS> $s2 = 'qwert6yuiop'
PS> $s2 -match '\d'
True

This time we get a positive result

The test for non numerics still works
PS> $s2 -match '\D'
True

 

Reverse a string

I sort of brushed over it on my last post but this is how you reverse a string.

 

function get-reversestring {
[CmdletBinding()]
param (
[string]$teststring
)

$ca = $teststring.ToCharArray()

[array]::Reverse($ca)

-join $ca
}

 

Take the input string and turn it into an array of chars. Use the reverse static method of the array class to reverse the array. Other useful array methods can be found in the documentation - https://docs.microsoft.com/en-us/dotnet/api/system.array?redirectedfrom=MSDN&view=netframework-4.7.2

-Join is used to stitch the reversed char array back into a string.

Test if a string is a palindrome

This is the first in a short series in which I’ll look at some string handling techniques. PowerShell is all about objects but sometimes you just have to work with the basics. In this post I’ll show how to test in a string is a palindrome.

 

A palindrome is a list of characters that read the same backwards as well as forwards. Radar is a word that is the same when reversed for example – its a simple palindrome. You can have phrases that are palindromes as well.

 

function test-palindrome {
[CmdletBinding()]
param (
[string]$teststring
)

Write-Verbose -Message "Input string: $teststring"
$cr = $teststring.ToCharArray()

$ca = $cr | where {$_ -match '\w'}

$clnstring = -join $ca
Write-Verbose -Message "Clean string: $clnstring"

[array]::Reverse($ca)

$revstring = -join $ca
Write-Verbose -Message "Reversed string: $revstring"

## make test case insensitive
if ($revstring -ieq $clnstring){
$true
}
else {
$false
}

}

 

There isn’t a method on the string class to reverse a string so convert the string to an array of chars then use Where-object to filter out non-word characters e.g. punctuation. Recreate the input string without the punctuation etc then use the Reverse static method on the array class. Use –join to create the reversed string from the char array.

 

Use –ieq (force case insensitive comparison) to test if the two strings are equal and return true or false accordingly.

 

Some simple examples:

PS> test-palindrome -teststring radar
True

PS> test-palindrome -teststring Radar
True

PS> test-palindrome -teststring Richard
False

 

And testing a phrase:

PS> test-palindrome -teststring "Madam, I'm Adam" -Verbose
VERBOSE: Input string: Madam, I'm Adam
VERBOSE: Clean string: MadamImAdam
VERBOSE: Reversed string: madAmImadaM
True

PS> test-palindrome -teststring 'The fat cat sat on the mat'
False

Third way to find pairs for given sum

There’s a third way to find pairs for given sum that’s a bit more complicated.

function get-pairs2 {
[CmdletBinding()]
param (
[int[]]$iarray,

[int]$value
)

$sarray = $iarray | Sort-Object

Write-Information -MessageData "Array: $iarray" -InformationAction Continue
Write-Information -MessageData "Sorted Array: $sarray" -InformationAction Continue
Write-Information -MessageData "Sum: $value" -InformationAction Continue

$left = 0
$right = $sarray.Count - 1

while ($left -lt $right){
Write-Verbose -Message "left = $left right =$right"
$sum = $sarray[$left] + $sarray[$right]

if ($sum -eq $value){
Write-Information -MessageData "Pair to give sum: ($($sarray[$left]), $($sarray[$right]))" -InformationAction Continue
$left += 1
$right -= 1
}
elseif ($sum -lt $value) {
$left += 1
}
elseif ($sum -gt $value){
$right -= 1
}
}
}

 

In this technique start by sorting the array. I’ve sorted it ascending which is the default.

 

Set the initial counters to the start and end of the sorted array. Use the while loop to work through the array. Sum the array elements and test if the sum equals the required value – if it does print the results and increment the left counter and decrement the low counter (move them closer together).

 

If the sum is less than than the required value increment the left counter and if its more decrement the right counter.

 

Eventually the counters will meet, the right counter will be greater than the left counter and the loop will finish.

 

This technique takes a bit of thinking about so this is a run with the counter values printed

PS> get-pairs2 -iarray $iarray -value 7 -Verbose
Array: 1 8 3 -3 6 4 9 5 10 2
Sorted Array: -3 1 2 3 4 5 6 8 9 10
Sum: 7
VERBOSE: left = 0 right =9
Pair to give sum: (-3, 10)
VERBOSE: left = 1 right =8
VERBOSE: left = 1 right =7
VERBOSE: left = 1 right =6
Pair to give sum: (1, 6)
VERBOSE: left = 2 right =5
Pair to give sum: (2, 5)
VERBOSE: left = 3 right =4
Pair to give sum: (3, 4)

 

Next time we’ll start to look at some string handling techniques

A more elegant way to find pairs

Last time I showed a brute force way to find the pairs of numbers in an array that would sum to a given value. This time I have a more elegant way to find pairs.

 

function get-pairs1 {
[CmdletBinding()]
param (
[int[]]$iarray,

[int]$value
)

Write-Information -MessageData "Array: $iarray" -InformationAction Continue
Write-Information -MessageData "Sum: $value" -InformationAction Continue

foreach ($n in $iarray){
$target = $value - $n

if ($target -in $iarray) {
Write-Information -MessageData "Pair to give sum: ($n, $target)" -InformationAction Continue
}
}
}

 

Iterate through the array and for each element subtract the element from the required value. Test to see if this result is a member of the array and print out the pair if it is.

 

This has the advantage of printing the pair each way so for an example array

Array: 1 8 3 -3 6 4 9 5 10 2

 

You’ll get

Pair to give sum: (1, 6)

and

Pair to give sum: (6, 1)

Find pairs that give required sum

If you have an array of integers how do you find pairs that give required sum. In other words which pairs of numbers add up to a given value.

 

There are a number of ways to solve this. Lets start with my favourite technique – brute force.

function get-pairs {
[CmdletBinding()]
param (
[int[]]$iarray,

[int]$value
)

Write-Information -MessageData "Array: $iarray" -InformationAction Continue
Write-Information -MessageData "Sum: $value" -InformationAction Continue

for ($i=0; $i -le ($iarray.Count -1); $i++){

for ($j= $i+1; $j -le ($iarray.Count -1); $j++){

if( ($iarray[$i] + $iarray[$j]) -eq $value) {

Write-Information -MessageData "Pair to give sum: ($($iarray[$i]), $($iarray[$j]))" -InformationAction Continue

}
} 
}
}

 

Start by outputting the array and the required value for reference. Iterate through the array then for each value compare that with the values ahead of it in the array. You don’t need to compare earlier values because they’ve already been done – counter intuitive but correct as if you have a 1 and a 6 in the array you only count them once not as 1 and 6 and 6 and 1.

PS> $iarray = 1,8,3,-3,6,4,9,5,10,2

 

PS> get-pairs -iarray $iarray -value 7
Array: 1 8 3 -3 6 4 9 5 10 2
Sum: 7
Pair to give sum: (1, 6)
Pair to give sum: (3, 4)
Pair to give sum: (-3, 10)
Pair to give sum: (5, 2)

 

There are more elegant and quicker solutions that I’ll cover in subsequent posts

Moving FSMO roles in PowerShell v6.1.1

With the Windows Server 2019 media now being available again it’s time to move my test lab over to the new version. I’d built a Windows Server 2019 VM and installed PowerShell v6.1.1. I discovered that in Server 2019 and the Windows 10 October 2018 update that the AD module worked in PowerShell v6.1.1. I decided to try moving FSMO roles in PowerShell v6.1.1 as I updated the domain and removed the old Server 2016 domain controller.

 

The usual schema update went smoothly – updated the schema version to 88 from 87. Installing AD domain services and DNS on the new DC worked. Promoting the Windows 2019 system to be a DC worked with no problems.

 

Time to move the FSMO roles. They would move automatically when the old DC was removed but its always better to control the action.

Import-Module ActiveDirectory

will load the AD module into PowerShell v6.1.1.

 

There are 5 FSMO roles – 2 at the forest level

PS> Get-ADForest | Format-List Name, *master

Name : Manticore.org
DomainNamingMaster : W16DC01.Manticore.org
SchemaMaster : W16DC01.Manticore.org

 

And 3 at the domain level – I only have a single domain to worry about.

PS> Get-ADDomain | Format-List *master, PDC*

InfrastructureMaster : W16DC01.Manticore.org
RIDMaster : W16DC01.Manticore.org
PDCEmulator : W16DC01.Manticore.org

 

The forest level FSMO roles moved:

PS> Move-ADDirectoryServerOperationMasterRole -Identity W19DC01 -OperationMasterRole DomainNamingMaster -Confirm:$false

PS> Move-ADDirectoryServerOperationMasterRole -Identity W19DC01 -OperationMasterRole SchemaMaster -Confirm:$false

PS> Get-ADForest | Format-List Name, *master

Name : Manticore.org
DomainNamingMaster : W19DC01.Manticore.org
SchemaMaster : W19DC01.Manticore.org

 

For the domain level FSMO roles I decided to get ambitious

PS> Move-ADDirectoryServerOperationMasterRole -Identity W19DC01 -OperationMasterRole RIDMaster, InfrastructureMaster, PDCEmulator -Confirm:$false

PS> Get-ADDomain | Format-List *master, PDC*

InfrastructureMaster : W19DC01.Manticore.org
RIDMaster : W19DC01.Manticore.org
PDCEmulator : W19DC01.Manticore.org

 

Moving FSMO roles in PowerShell v6.1.1 was successful

Active Directory cmdlets in PowerShell v6.1.1

Just discovered that you can run the Active Directory cmdlets in PowerShell v6.1.1 BUT there is a huge caveat.

 

The Windows 10 October 2018 (Windows 10 1809) update includes the RSAT tools (including the AD tools) as optional features. This means that you can easily install the AD tools:

Add-WindowsCapability -Name Rsat.ActiveDirectory.DS-LDS.Tools~~~~0.0.1.0 –Online

 

The AD PowerShell module now has a 1.0.1.0 version with the PSEdition set as Core,Desk

 

I’m running the Windows 10 Insider Preview build 18282 which has moved on a bit from Windows 10 1809 and PowerShell Core v6.1.1.

 

The AD module can be imported and the commands that I’ve tried have worked.

 

For the AD cmdlets to work in PowerShell Core looks like you need Windows 10 October 2018 update or later and PowerShell v6.1.1 or later. I’m going to say you should upgrade to v6.1.1 if you have v6.1 as the later version fixes a .NET security bug.

 

This is a big step forward for PowerShell Core being an acceptable replacement for Windows PowerShell though there are still a few gaps to be filled.

Reverse an array

Ever needed to reverse an array?

If its sorted then sorting in the opposite direction will work. Most arrays aren’t sorted so you need to use the Reverse static method of the array class

 

Here’s some examples

$carray = 'a','b','c','d','e','f','g','h','i','j','k','l','m','n','o','p','q','r','s','t','u','v','w','x','y','z'
$carray -join ','
[array]::Reverse($carray)
$carray -join ','

 

$iarray = 1,2,3,4,5,6,8,9,10
"$iarray"
[array]::Reverse($iarray)
"$iarray"

 

$psa = Get-Process p*
$psa
[array]::Reverse($psa)
$psa

 

The thing to note is that the array is reversed rather than creating output so if you do this

$iarray = 1,2,3,4,5,6,8,9,10
$newary = [array]::Reverse($iarray)

$iarray is reversed and $newary is empty!

 

If you need the original and reversed arrays take a copy of the original and then reverse one of them.

Hyper-V book now available

My Hyper-V book now available.

 

Ebook direct from the publisher: https://www.apress.com/gb/book/9781484241158#otherversion=9781484241165

 

The Kindle version is on Amazon UK:

https://www.amazon.co.uk/s/ref=nb_sb_noss_2?url=search-alias%3Daps&field-keywords=hyper-v+2019&rh=i%3Aaps%2Ck%3Ahyper-v+2019

Presumably other Amazon sites will follow soon

 

The paper back version is on pre-order from Apress and Amazon to be available on 25 December 2018 – Happy Christmas