How are binary octet string converted from binary to guid? - active-directory

In Active Directory, I see that objectGUID are octet string binary 16 bytes fields. How is this conversion happening?
Is the binary converted to octetstring by splitting the fields in chunks? Like a Uint8Array?
How does it eventually become something like:
{XXXXXXXX-XXXX-XXXX-XXXX-XXXXXXXXXXXX}

I just had to do this myself and found a PowerShell snippet that I had from over a decade ago, I tested it today and it still works.
The first line of code removes the backlash character in case your octet string is in the following format: '\bb\85\43\3e\43\7c\eb\4f\8e\a2\97\c6\5c\c0\6a\bf'
Input: $OctetString = '\bb\85\43\3e\43\7c\eb\4f\8e\a2\97\c6\5c\c0\6a\bf'
Output: '3e4385bb-7c43-4feb-8ea2-97c65cc06abf'
{
$OctetString = ($OctetString -replace '\\', '')
[UInt32]$a = [Convert]::ToUInt32(($OctetString.Substring(6, 2) + $OctetString.Substring(4, 2) + $OctetString.Substring(2, 2) + $OctetString.Substring(0, 2)), 16)
[UInt16]$b = [Convert]::ToUInt16(($OctetString.Substring(10, 2) + $OctetString.Substring(8, 2)), 16)
[UInt16]$c = [Convert]::ToUInt16(($OctetString.Substring(14, 2) + $OctetString.Substring(12, 2)), 16)
[Byte]$d = ([Convert]::ToUInt16($OctetString.Substring(16, 2), 16) -as [byte])
[Byte]$e = ([Convert]::ToUInt16($OctetString.Substring(18, 2), 16) -as [byte])
[Byte]$f = ([Convert]::ToUInt16($OctetString.Substring(20, 2), 16) -as [byte])
[Byte]$g = ([Convert]::ToUInt16($OctetString.Substring(22, 2), 16) -as [byte])
[Byte]$h = ([Convert]::ToUInt16($OctetString.Substring(24, 2), 16) -as [byte])
[Byte]$i = ([Convert]::ToUInt16($OctetString.Substring(26, 2), 16) -as [byte])
[Byte]$j = ([Convert]::ToUInt16($OctetString.Substring(28, 2), 16) -as [byte])
[Byte]$k = ([Convert]::ToUInt16($OctetString.Substring(30, 2), 16) -as [byte])
[Guid]$guid = New-Object Guid($a, $b, $c, $d, $e, $f, $g, $h, $i, $j, $k)
return $guid.Guid
}
In case you want to convert the other direction:
Input: $guid= '3e4385bb-7c43-4feb-8ea2-97c65cc06abf'
Output: '\bb\85\43\3e\43\7c\eb\4f\8e\a2\97\c6\5c\c0\6a\bf'
{
$stringGuid = [Guid]"{$guid}"
$octetGuid = $null
foreach ($byte in $stringGuid.ToByteArray()) {
$octetGuid += '\' + $byte.ToString('x2')
}
return $octetGuid
}

Related

Powershell split an array into 5 arrays with equal length

Hello everyone hope you are all doing great! been searching but cannot get it right :( could it be possible for you to help me, please?
Need to split an array into 5 arrays with equal length, for example.
$MainArray = #(1,2,3,4,5,6,7,8,9,10,11)
Result:
array1 = 1,2,3
array2 = 4,5
array3 = 6,7
array4 = 8,9
array5 = 10,11
Each array as even as possible (order doesn't matters) has this and it splits but not as even as I would like to.
Currently, I have this (searched on the internet already)
function Split-Array {
[CmdletBinding()]
param(
[Object] $inArray,
[int]$parts
)
if ($inArray.Count -eq 1) { return $inArray }
$PartSize = [Math]::Ceiling($inArray.count / $parts)
$outArray = New-Object 'System.Collections.Generic.List[psobject]'
for ($i = 1; $i -le $parts; $i++) {
$start = (($i - 1) * $PartSize)
$end = (($i) * $PartSize) - 1
if ($end -ge $inArray.count) {$end = $inArray.count - 1}
$outArray.Add(#($inArray[$start..$end]))
}
return , $outArray
}
Split-array -inArray $MainArray -parts 5
This function splits the $MainArray into 5 arrays but not as even, the result is:
array1 = 1,2,3
array2 = 4,56
array3 = 7,8,9
array4 = 10,11
array5 = 11
It even errors adding 11 into 2 arrays. My brain is burned at this moment, haha any help would be much appreciated. thanks!
To perform the element distribution as requested - with extra elements getting added to the initial output arrays - use the following.
function Split-Array {
[CmdletBinding()]
param(
[object[]] $inArray,
[int] $parts
)
[int] $partSize = [Math]::Floor($inArray.count / $parts)
if ($partSize -eq 0) { throw "$parts sub-arrays requested, but the input array has only $($inArray.Count) elements." }
$extraSize = $inArray.Count - $partSize * $parts
$offset = 0
foreach ($i in 1..$parts) {
, $inArray[$offset..($offset + $partSize + [bool] $extraSize - 1)]
$offset += $partSize + [bool] $extraSize
if ($extraSize) { --$extraSize }
}
}
Note:
[bool] casts are used as a convenient shortcut to map nonzero values to 1 and zero to 0, via using the resulting [bool] in the context of calculations.
.. - the range operator - is used to extract array slices from the input array, and also as a simple way to loop $parts times via a foreach loop.
, - the array constructor operator - is used in its unary form to output each array slice as a whole - see this answer for an explanation.
Sample call, which uses ConvertTo-Json to visualize the results:
Split-array -inArray (1..11) -parts 5 |
ConvertTo-Json
Output (5 arrays with 2-3 elements each):
[
[
1,
2,
3
],
[
4,
5
],
[
6,
7
],
[
8,
9
],
[
10,
11
]
]
If you keep track of the arrays created, you should be able to get the results you're after:
Function Split-Array {
Param(
[object]$InputObject,
[int]$Chunks
)
$track = 1
while ($InputObject.Count -gt 0 -and $track -le $Chunks) {
$chunk_size = [Math]::Min($InputObject.Count, [Math]::Ceiling($InputObject.Count / ($Chunks - $track + 1)))
$chunk = $InputObject[0..($chunk_size - 1)]
$InputObject = $InputObject[$chunk_size..($InputObject.Count - 1)]
,$chunk
$track++
}
}
The while loop starts, and it will keep executing as long as either of these conditions are met:
$array.Count -gt 0: The count of elements in $array is greater than
0. This means that there are still elements in $array that need to be split into separate arrays.
$arrayIndex -le $arrayCount: The number of arrays created so far is
less than or equal to $arrayCount. This means that you haven't
created the desired number of arrays yet.

Send information about hardware of my computer to a database

I created a powershell script in order to send information about my computer hardware to a database. Unfortunately, when I run my program I get these errors:
Impossible de convertir la valeur « HDDused : » en type « System.Double ». Erreur : « Le format de la chaîne d'entrée est incorrect. »
Au caractère D:\projet\new2.ps1:43 : 1
"HDDused : " - $HDDused
My code is :
function Get-Temperature {
$t = Get-WmiObject MSAcpi_ThermalZoneTemperature -Namespace "root/wmi"
$returntemp = #()
foreach ($temp in $t.CurrentTemperature)
{
$currentTempKkelvin = $temp / 10
$currentTempCelsius = $currentTempKelvin
$reeturntemp = $currentTempCelsius
}
return $returntemp
}
#Get-Counter -Counter "\GPU Engine(*)\Utilization Percentage"
$CpuTemp = Get-Temperature
$CpuTemp = $cpuTemp -as [float]
"CpuTemp : " + $CpuTemp
$CpuUsage = Get-Counter -Counter "\Processeur(_total)\% temps processeur" | ForEach-Object {$_.CounterSamples[0].CookedValue}
$CpuUsage = $CpuUsage -as [float]
"CpuUsage : " + $CpuUsage
$TotalMemoire = Get-CimInstance Win32_PhysicalMemory | Measure-Object -Property capacity -Sum | Foreach {"{0:N2}" -f ([math]::round(($_.Sum / 1GB),2))}
$TotalMemoire = ($TotalMemoire -as [float])/100
#$TotalMemoire
$RAMfree = Get-Counter -Counter "\Mémoire\Octets disponibles" | ForEach-Object {$_.CounterSamples[0].CookedValue}
$RAMfree = ($RAMfree -as [float])/1E+09
"RAMfree : " + $RAMfree
$RAMused = ($TotalMemoire - $RAMfree)
"RAMused : " + $RAMused
$HDDfree = Get-Counter -Counter "\Disque logique(C:)\Mégaoctets libres" | ForEach-Object {$_.CounterSamples[0].CookedValue}
$HDDfree = ($HDDfree -as [float])/1000
"HDDfree : " + $HDDfree
$HDDused = Get-PSDrive C | ForEach-Object {$_.Used}
$HDDused = ($HDDused -as [float])/1E+09
"HDDused : " - $HDDused
#$AddMac = Get-NetAdapteer | ? { $_.name -eq ""ethernet" } | Select-0bject -ExpandProperty macaddress
#"Adresse MAC : " + $AddMac
$cpuApp = 0
$cpuTemp = 0
$cpuUsage = 0
$infos = #{
CpuTemp = $CpuTemp
CpuUsage = $CpuUsage
CpuApp = $CpuApp
RAMfree = $RAMfree
RAMused = $RAMused
HDDfree = $HDDfree
HDDused = $HDDused
CguTemp = $CguTemp
CguUsage = $CguUsage
#AddMac = $AddMac
}
Invoke-WebRequest -URI 'http://172.31.6.204/elle/public/login' -Method POST -Body $infos
Can you help me please ? Thanks.
You have several typos in your code, there is an e too much here:
$ree!turntemp = $currentTempCelsius
And what's the point of iterating through the temperatures when you only use the last one?
But the thing that is complained about is:
"HDDused : " - $HDDused
You are subtracting a number from a string instead of doing string concatenation. Use a plus as you do the other places.
Get-NetAdapteer has been commented away, but that also has an e too much.

Using Get-Random after using Where-Object creates a null valued expression

I'm trying to create a 10 character password that includes a mix of numbers, letters (uppercase and lowercase), and symbols.
Below is the script I am using in the function:
Function Get-TempPassword {
$TempPassword = $null
$ascii = $NULL;For ($a = 33;$a –le 126;$a++) {$ascii +=, ([char][byte]$a | Where-Object {$_ -notin "'",'`','|','_',"`;",'"',','})}
Do {$TempPassword += $ascii | Get-Random; $loop++}
Until ($loop -eq 11)
return $TempPassword
}
If I remove the following section:
| Where-Object {$_ -notin "'",'`','|','_',";",'"',','}
The creation of the password works fine albeit including the symbols I don't want included.
Having the Where-Object function causes the Get-Random function to only use the first 5 characters in the array, and therefore I don't get letters of any case type, or numbers, or any of the other symbols.
I've found that if I use $ascii[26] (being the 25th character in the array) I get a null value, however I would think this would allow any character up to this character to be used, or none at all, not just the first 5. The 25th character just so happens to be a ; (ascii value number 59). I tried adding the symbol to the Where-Object exclusion, and it was removed from the array, but the 25th character still showed as a null value.
I performed a reverse lookup of the ascii value [int[]][char[]] of each character either side of where the ; symbol would appear and it returned values 58 and 60, leading me to believe it was value 59 that was offending, but the symbol at this point should have been excluded.
Adding characters to the 'where-object' exclusion list should be removing them from the array, and it appears to, however running $ascii.Count shows 49 characters, regardless of whether I add or remove characters to the Where-Object exclusion list.
I have looked for information on the web and can't seem to find any, although it may be the search terms I'm using, as it's a bit of a complex case that not many would be reporting on.
Any help is appreciated.
I didn't write this and i can't remember where i got it but i have built this into any scripts to create random secure Windows passwords, you can specify the length of the password returned by the param [int]$PasswordLength ( i have already set it to 10 ).
function New-SWRandomPassword {
[CmdletBinding(DefaultParameterSetName='FixedLength',ConfirmImpact='None')]
[OutputType([String])]
Param
(
# Specifies minimum password length
[Parameter(Mandatory=$false,
ParameterSetName='RandomLength')]
[ValidateScript({$_ -gt 0})]
[Alias('Min')]
[int]$MinPasswordLength = 8,
# Specifies maximum password length
[Parameter(Mandatory=$false,
ParameterSetName='RandomLength')]
[ValidateScript({
if($_ -ge $MinPasswordLength){$true}
else{Throw 'Max value cannot be lesser than min value.'}})]
[Alias('Max')]
[int]$MaxPasswordLength = 11,
# Specifies a fixed password length
[Parameter(Mandatory=$false,
ParameterSetName='FixedLength')]
[ValidateRange(1,2147483647)]
[int]$PasswordLength = 10,
# Specifies an array of strings containing charactergroups from which the password will be generated.
# At least one char from each group (string) will be used.
[String[]]$InputStrings = #('abcdefghijkmnpqrstuvwxyz', 'ABCEFGHJKLMNPQRSTUVWXYZ', '23456789', '!"#%&'),
# Specifies a string containing a character group from which the first character in the password will be generated.
# Useful for systems which requires first char in password to be alphabetic.
[String] $FirstChar,
# Specifies number of passwords to generate.
[ValidateRange(1,2147483647)]
[int]$Count = 1
)
Begin {
Function Get-Seed{
# Generate a seed for randomization
$RandomBytes = New-Object -TypeName 'System.Byte[]' 4
$Random = New-Object -TypeName 'System.Security.Cryptography.RNGCryptoServiceProvider'
$Random.GetBytes($RandomBytes)
[BitConverter]::ToUInt32($RandomBytes, 0)
}
}
Process {
For($iteration = 1;$iteration -le $Count; $iteration++){
$Password = #{}
# Create char arrays containing groups of possible chars
[char[][]]$CharGroups = $InputStrings
# Create char array containing all chars
$AllChars = $CharGroups | ForEach-Object {[Char[]]$_}
# Set password length
if($PSCmdlet.ParameterSetName -eq 'RandomLength')
{
if($MinPasswordLength -eq $MaxPasswordLength) {
# If password length is set, use set length
$PasswordLength = $MinPasswordLength
}
else {
# Otherwise randomize password length
$PasswordLength = ((Get-Seed) % ($MaxPasswordLength + 1 - $MinPasswordLength)) + $MinPasswordLength
}
}
# If FirstChar is defined, randomize first char in password from that string.
if($PSBoundParameters.ContainsKey('FirstChar')){
$Password.Add(0,$FirstChar[((Get-Seed) % $FirstChar.Length)])
}
# Randomize one char from each group
Foreach($Group in $CharGroups) {
if($Password.Count -lt $PasswordLength) {
$Index = Get-Seed
While ($Password.ContainsKey($Index)){
$Index = Get-Seed
}
$Password.Add($Index,$Group[((Get-Seed) % $Group.Count)])
}
}
# Fill out with chars from $AllChars
for($i=$Password.Count;$i -lt $PasswordLength;$i++) {
$Index = Get-Seed
While ($Password.ContainsKey($Index)){
$Index = Get-Seed
}
$Password.Add($Index,$AllChars[((Get-Seed) % $AllChars.Count)])
}
Return $(-join ($Password.GetEnumerator() | Sort-Object -Property Name | Select-Object -ExpandProperty Value))
}
}
}
New-SWRandomPassword
EDIT:::
https://gallery.technet.microsoft.com/scriptcenter/Generate-a-random-and-5c879ed5
The script can be found here.
Short version (best method for me):
$possible=36..38 + 40..43 + 45..58 + 60..94 + 97..123 + 125..126 + 33
(get-random -count 10 -input $possible | % {[char]$_}) -join ''
Using the following script seems to have worked exactly how I want.
I removed the comma (,) from after += on this line:
$ascii = $NULL;For ($a = 33;$a –le 126;$a++) {$ascii +=, ([char][byte]$a | Where-Object {$_ -notin "'",'`','|','_',";",'"',','})}
I created a blank array before the array is added to:
$ascii = #()
The full code block is below:
Function Get-TempPassword {
$TempPassword = $null
$ascii = #()
For ($a = 33;$a –le 126; $a++) { $ascii += ([char][byte]$a | Where-Object { $_ -notin "'",'`','|','_',";",'"',',' }) }
Do {$TempPassword += $ascii | Get-Random; $loop++}
Until ($loop -eq 11)
return $TempPassword
}
Recursive method :
Function random-password ($length = 10)
{
$Assembly = Add-Type -AssemblyName System.Web
$password = [System.Web.Security.Membership]::GeneratePassword($length, 2)
$desablechar = "[``'|_;,`"]"
if ($password -match $desablechar )
{
random-password $length
}
else
{
$password
}
}
random-password
try Something like this :
Function random-password ($length = 10)
{
$possible=36..38 + 40..43 + 45..58 + 60..94 + 97..123 + 125..126 + 33
$password = get-random -count $length -input $possible |
% -begin { $aa = $null } -process {$aa += [char]$_} -end {$aa}
return $password
}
random-password
I have rectified my others propositions, but i propose an other method :)
Function random-password2 ($length = 10)
{
$Assembly = Add-Type -AssemblyName System.Web
$password = [System.Web.Security.Membership]::GeneratePassword(50, 2)
$possible=36..38 + 40..43 + 45..58 + 60..94 + 97..123 + 125..126 + 33
$newchar=[char](get-random -count 1 -input $possible)
$password=$password -replace "[`'|_;,]", $newchar
$password.Substring(0, $length)
}
random-password2

Subroutine that takes average of one or more arrays

I'm working on a subroutine that takes the average of 1 or more arrays. I would like to do this without using a module.
use strict;
use warnings;
use List::Util 'sum';
my #w = (0, 2);
my #x = (1, 3);
my #y = (2, 2);
my #z = (1, 1);
# the average of these four arrays is (1,2) since
# (0+1+2+1)/4 = 1 and (2+3+2+1)/4 = 2
my #arrays = \(#w, #x, #y, #z);
my #avg;
# this is the way to do it using the module
for my $i (0..$#w) {
$avg[$i] = sum(map $_->[$i], #arrays) / #arrays;
}
print "#avg\n";
# my way of doing it without module
#avg;
for my $i (0..$#w) {
$avg[$i] = prod_sum(map $_->[$i], \#arrays) / #arrays;
}
print "#avg\n";
# subroutines
sub prod_sum{
my $o = $_[0];
my $arr_ref = $_[1];
my $array_ref;
foreach my $row (#$arr_ref){
foreach my $cell (#$row) {
push(#{ $array_ref }, $_);
}
}
my $sum = $o + the_sum($array_ref);
return $sum;
}
sub the_sum{
my $sum = 0;
for ( #{$_[0]} ) {
$sum += $_;
}
return $sum;
}
output
1 2
[pair of really random big numbers]
The first output is correct. It displays the average of all of the arrays. The second output is completely wrong. How do I do this without using a module?
I propose this solution:
use strict;
use warnings;
my #w = (0, 2);
my #x = (1, 3);
my #y = (2, 2);
my #z = (1, 1);
my #arrays = \(#w, #x, #y, #z);
my ($x, $y) = (0, 0);
foreach my $arr(#arrays) {
$x += $arr->[0];
$y += $arr->[1];
}
my #result = ( $x / #arrays, $y / #arrays);
print "(#result)", "\n"; # <---- prints (1 2)
You think sum is being passed two variables, it is not. It is only being passed an array. Modify your prod_sum to expect only an array (and replace \#arrays in the call of prod_sum to be just #arrays). Or you can use this:
sub sum {
return 0 if $#_ < 0;
my $head = shift;
return $head + sum(#_);
}
The above is a recursive subroutine that will sum an array.
Note: if your array has more then 100 element, use warnings will emit a deep recursion warning. For more on that topic, see here

Taking the average of many N sized arrays

Can anyone help me fix this? I'm trying to write a script that takes the sum of many N sized arrays. In the example below the average of the arrays would be (1,2) since (0+1+2+1)/4 = 1 and (2+3+2+1)/4 = 2. Currently the code below only works for arrays of size 2. How would I do this with arrays of say size 100 such that the length of #results is 100? I imagine I would need a counter right?
use strict;
use warnings;
my #w = (0, 2);
my #x = (1, 3);
my #y = (2, 2);
my #z = (1, 1);
my #arrays = \(#w, #x, #y, #z);
my ($x, $y) = (0, 0);
foreach my $arr(#arrays) {
$x += $arr->[0];
$y += $arr->[1];
}
my #result = ( $x / #arrays, $y / #arrays);
print "#result\n"; # <---- prints 1 2
#######
# my attempt
my #avg;
for my $i(0..$w) {
# I'm guessing the result 'map...' returns is an array
#avg[$i] = sum(\(map $_->[$i], #arrays)) / #arrays;
}
# sum the elements in an array and return its value
sub sum{
# takes 1 param: an arrey_ref
my $sum = 0;
for ( #{$_[0]} ) {
$sum += $_;
}
return $sum;
}
My attempt is close but it doesn't work. I would like to do this without using a module.
This is my solution:
use strict;
use warnings;
my $SIZE = 3;
my #w = (0, 2, 3);
my #x = (1, 3, 4);
my #y = (2, 2, 6);
my #z = (1, 1, 3);
my #arrays = \(#w, #x, #y, #z);
my #result = ();
foreach my $arr(#arrays) {
for(my $i=0; $i<$SIZE; $i++) {
$result[$i] += $arr->[$i];
}
}
#result = map { $_ / #arrays } #result;
print "(#result)", "\n"; # <---- prints (1 2 4)
Do it in a simple way, like this:
#!/usr/bin/env perl
use strict;
use warnings;
my #w = (1, 2, 3, 4);
my #x = (1, 2, 3, 4);
my #y = (1, 2, 3, 4);
my #z = (1, 2, 3, 4);
my #arrays = \(#w, #x, #y, #z);
my #sums;
foreach my $arr(#arrays) {
for( my $i = 0; $i <= $#w; $i++, $j++ )
{
$sums[$j] += $arr->[$i];
}
}
my #avg = map { $_ / #arrays } #sums;
foreach( #avg )
{
print "$_ ";
}
print "\n";
Yes its very close. Here are the corrections to the problem code:
my #avg;
for my $i (0..$#w) {
my #transposed = map {$_->[$i]} #arrays;
$avg[$i] = sum(\#transposed) / #transposed;
# or in one line: $avg[$i] = sum( [map {$_->[$i]} #arrays] ) / #arrays;
}
(I'm assuming that the arrays #w, #x, #y and #z are all the same size.)
Note that #avg[$i] is an array slice. You want $avg[$i] to specify a particular position.
The List::Util module can be very useful for problems like this. Together with a simple average subroutine it makes everything very simple.
use strict;
use warnings;
use List::Util 'sum';
sub average { sum(#_) / #_ }
my #w = (0, 2);
my #x = (1, 3);
my #y = (2, 2);
my #z = (1, 1);
my #arrays = \(#w, #x, #y, #z);
my #results = map {
my $i = $_;
average(map $_->[$i], #arrays);
} 0 .. $#{$arrays[0]};
print "#results\n";
output
1 2
map does not return an array. docs
Change
#avg[$i] = sum(\(map $_->[$i], #arrays)) /#arrays;
to
$avg[$i] = sum( map $_->[$i], #{$arrays[$i]} ) / #{$arrays[$i]};
and change
sub sum{
my $sum = 0;
for ( #{$_[0]} ) {
$sum += $_;
}
return $sum;
}
to
sub sum {
my $sum;
$sum += $_ for #_;
return $sum;
}

Resources