Showing posts with label functions. Show all posts
Showing posts with label functions. Show all posts

Tuesday, October 13, 2009

Secure-Phrase

"When in the Course of human events it becomes necessary for one people to..." completely secure everything they have, but are running out of passwords, a tool must be created to convert existing phrases known by the user to a secure passphrase. That time is now, and the tool is below:

SCRIPT

param (

  [string]$convert, #phrase to convert to passphrase
  [switch]$poss #ask for total phrases possible
)

$ErrorActionPreference = "SilentlyContinue"

function GenRand ($char) { # returns a random number between 0 and the input string length
  $random = $rand.Next(0,($char.Count))
  Start-Sleep -m 1
  $char[$random]
}

function GenPoss ($text) { # generates the number of possible outputs for a specific character or phonetic string
  $possible = 1
  $chars = (0..($text.Length - 1)) | % { $text[$_] }
  foreach ($char in $chars) {
    foreach ($count in (0..($alpha.Count - 1))) {
      $alphaMatch = $alpha[$count][0]
      if ($char -match $alphaMatch) { $match = $true ; break }
    }
    if ($match) { $possible *= $alpha[$count].Count ; $match = $false }
    else {
      foreach ($spec in $special) {
        if ($char -match $spec) { $match = $true ; break }
      }
      if ($match) { $possible *= $special.Count ; $match = $false }
    }
  }
  return $possible
}

$rand = New-Object System.Random

$a = "a","A","4","`@"
$b = "b","B","8"
$c = "c","C","`("
$d = "d","D"
$e = "e","E","3"
$f = "f","F","ph"
$g = "g","G","6"
$h = "h","H"
$i = "i","I","`!","1"
$j = "j","J"
$k = "k","K"
$l = "l","L","`|"
$m = "m","M"
$n = "n","N"
$o = "o","O","0"
$p = "p","P","`?"
$q = "q","Q","9"
$r = "r","R"
$s = "s","S","`$","5"
$t = "t","T","7","`+"
$u = "u","U"
$v = "v","V"
$w = "w","W"
$x = "x","X","`*"
$y = "y","Y"
$z = "z","Z"
$space = " ","_","-"

$ate = "ate","8"
$eat = "eat","8"
$any = "any","ne"
$one = "one","1"
$won = "won","1"
$ph = "ph","f"
$oo = "oo","u"
$ck = "ck","k"
$ew = "ew","oo"
$two = "two","too","to"

$to = "to","two","too"
$too = "too","to","two"
$0 = "0","O","o"

$1 = "1","one","won"
$2 = "2","two","to","too"
$3 = "3","three"
$4 = "4","four","fore","for"
$5 = "5","five"
$6 = "6","six"
$7 = "7","seven"
$8 = "8","eight","ate"
$9 = "9","nine"
$special = "`~","`!","`@","`#","`$","`%","`^","`&","`*","`(","`)","`_","`+","`\{","`}","`|","`:","`"","`<","`>","`?","``","`-","`=","`[","`]","`\","`;","`'","`,","`.","`/"

$alpha = @($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,$space)
$phone = @($ate,$eat,$any,$one,$won,$ph,$oo,$ck,$ew,$two,$to,$too,$0,$1,$2,$3,$4,$5,$6,$7,$8,$9)

$text = $convert

foreach ($count in (0..($phone.Count-1))) {
  $old = $phone[$count][0]
  $new = GenRand ($phone[$count])
  $text = $text.Replace($old,$new)
}

$chars = (0..($text.Length - 1)) | % { $text[$_] }
$newChars = ""

foreach ($char in $chars) {
  foreach ($count in (0..($alpha.Count - 1))) {
    $alphaMatch = $alpha[$count][0]
    if ($char -match $alphaMatch) { $match = $true ; break }
  }
  if ($match) { $newChars += GenRand $alpha[$count] ; $match = $false }
  else {
    foreach ($spec in $special) {
      if ($char -match $spec) { $match = $true ; break }
    }
    if ($match) { $newChars += GenRand $special ; $match = $false }
    else { $newChars += $char }
  }
}

if ($poss) {
  $possible = 1
  foreach ($count in (0..($phone.Count-1))) {
    if ($convert -match $phone[$count][0]) { $possible *= GenPoss ($phone[$count][0]) }
  }
  $possible *= GenPoss $convert
}

if ($poss) { Write-Host "Password:" $newChars ; Write-Host "Possible:" $possible }
else { $newChars }
 code: copy : expand : collapse

USAGE
.\Secure-Phrase.ps1 "text_to_convert" [-p]
This will output a the text given using random replacements of the characters with the given set within $alpha.  The "-p" optional switch shows the total number of possibilites for the input text.

EXAMPLES
PS > (0..9) | % { .\Secure-Phrase.ps1 "convertme" }
C0nveR7M3

c0nvertMe
(ONV3r+ME
CONVeRTM3
cOnver+m3
conV3RtM3
(ONveR7Me
COnvErtMe
cONvER7mE
coNver7Me
Create 10 randomized passphrases from "convertme"

PS >.\Secure-Phrase.ps1 "convertme" -p
Password: CoNveRTme
Possible: 5184
Create a single passphrase from "convertme" and show the total number of possible passphrases

PS >.\Secure-Phrase.ps1 "!@#$%^&"
@/|&!.$
Create a single passphrase from !@#$%^

NOTE
The script will accept special characters and numbers.

Thursday, October 1, 2009

ConvertSID

Many times while looking at event logs or parsing through a registry the SID of an account is listed instead of the actual logon domain and name. PoSh it and convert it. Let's see what we get!

FUNCTION

function ConvertSID ($sid) {
  $secID = New-Object System.Security.Principal.SecurityIdentifier $sid
  ($secID.Translate([System.Security.Principal.NTAccount])).Value
}
 code: copy : expand : collapse

Simply pass this function an acutal SID and it will return the account name associated to it.

USAGE
ConvertSID S-1-5-18

This will return NT AUTHORITY\SYSTEM

Wednesday, September 30, 2009

SetNTFSOwner

So, it has been quite a while now since my last blog, and i'm starting to go into the DT's. Finally, I have some release!

One of my glorious tasks I have in my current role is to migrate File servers due to lifecycle events, acquisitions, upgrades...what-nots. While doing this users have a tendancy of copying data to their local workstation, then moving it back. Welcome to maintained Ownership of files/folders. Part of my team's responsiblities is to manage NTFS permisions on our servers. When the Owner is set to anything other than "BUILTIN\Administrators" permissions abilities can be lost until the local group has been given ownership again.

One of my best friends in PoShing is Google. Now, search google for powershell set ntfs owner and you'll find blisteringly long scripts and confusing answers, even some that say you must use third-party cmdlets. Lets do this as simple as possible, natively in PoSh:

FUNCTION

function SetNTFSOwner {
  param (
    [string]$path,
    [string]$owner
  )

  $children = Get-ChildItem $path -Recurse | % {$_.FullName} foreach ($child in $children) {
    $acl = Get-Acl $child
    $split = $owner.Split("\")
    if ($acl.Owner -ne $owner) {
        if ($owner -match "BUILTIN") { $objGroup = New-Object System.Security.Principal.NTAccount($split[1]) }
        else { $objGroup = New-Object System.Security.Principal.NTAccount($split[0],$split[1]) }
        $strSID = $objGroup.Translate([System.Security.Principal.SecurityIdentifier])
        $acl.SetOwner($strSID)
    }
    Set-Acl -Path $child -AclObject $acl
  }
}
 code: copy : expand : collapse

STEP-BY-STEP
param (
    [string]$path,
    [string]$owner
)
Our script will take two parameters, and both are required: -path and –owner. The information must be passed to know what folders need changed, and who the owner should be.

$children = Get-ChildItem $path -Recurse | % {$_.FullName}
From the path we need to get all child folders and files. Gathering just the parent level could leave trailing files or folders that had still other owners set.

$acl = Get-ACL $child
Get-ACL gathers the security of the individual file/folder

$split = $owner.Split("\")
splits the $owner string into an object with two values

if ($acl.Owner -ne $owner)
Here we’ll validate the current Owner against our preferred Owner. There is no reason to spend the cycles setting ACL’s if they are already correct.

if ($owner -match "BUILTIN") { $objGroup = New-Object System.Security.Principal.NTAccount($split[1]) }
else { $objGroup = New-Object System.Security.Principal.NTAccount($split[0],$split[1]) }
When retrieving accounts with the System.Security.Principal.NTAccount .NET Class Local and Domain accounts must be handled differently. Local accounts use a single string to retrieve; the User/Group name only. Domain accounts must use two strings; the Domain and User/Group name.

$strSID = $objGroup.Translate([System.Security.Principal.SecurityIdentifier])
$acl.SetOwner($strSID)
The SID for the account is translated from the NTAccount using the .NET class System.Security.Principal.SecurityIdentifier. The unique SID must be passed using the .SetOwner method of our collected ACL.

We now have the corrected settings stored in our object $acl. It’s time to write it back to our file/folder.

Set-Acl -Path $child -AclObject $acl
Since we gathered the ACL using Get-ACL the object is in correct format already. It is simply set back to the object we gathered it from.

Bingo, Done!

It is important to know that this script should be run from the local workstation or sever to where the data resides. It can be run on a remote file store passing the path using its full UNC and the group name as “%COMPUTERNAME%\%GROUP”, but will be extremely slow.

USAGE
SetNTFSOwner "folder\or\file" "DOMAIN\owner"
This function can be piped to easily. If you wanted to set the owner on all subdirectories, but not the parent simply:
Get-ChildItem %PATH% | % {SetNTFSOwner $_ "DOMAIN\Owner"
or for a list already gathered:
Get-Content %file% | % {SetNTFSOwner $_ "DOMAIN\Owner"

ALIASES
% = ForEach-Object

Thursday, September 17, 2009

Random Password Generator

One more function.  This is extremely late, so I won't comment much about it, but check it out anyways.

FUNCTION

function GenPwd ($CharLen) {
  $alphaLow = "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"
  $alphaCap = "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"
  $numb = "1","2","3","4","5","6","7","8","9"
  $special = "`~","`!","`@","`#","`$","`%","`^","`&","`*","'(","`)","`_","`+","`|","'{","`}","`:","`"","`<","`>","`?","``","`-","`=","`\","`[","`]","`;","`'","`,","`.","`/"
  $aLLen = $alphaLow.Length
  $aCLen = $alphaCap.Length
  $nLen = $numb.Length
  $sLen = $special.Length
  $rand = New-Object System.Random
  $generate = (0..($CharLen - 1)) | % {
    $rand.Next(0,4)
    Start-Sleep -m 1
  }

  $generated = [regex]::split($generate," ")
  foreach ($number in $generated) {
    if ($number -eq 0) { $charNumb = $rand.Next(0,([Int32]$aLLen - 1)) ; $char += $alphaLow[$charNumb] ; Start-Sleep -m 1 }
    elseif ($number -eq 1) { $charNumb = $rand.Next(0,([Int32]$aCLen - 1)) ; $char += $alphaCap[$charNumb] ; Start-Sleep -m 1 }
    elseif ($number -eq 2) { $charNumb = $rand.Next(0,([Int32]$nLen - 1)) ; $char += $numb[$charNumb] ; Start-Sleep -m 1 }
    elseif ($number -eq 3) { $charNumb = $rand.Next(0,([Int32]$sLen - 1)) ; $char += $special[$charNumb] ; Start-Sleep -m 1 }
  }
  return $char
}
 code: copy : expand : collapse

USAGE
GenPwd [count]
Where [count] is the number of characters for the password.

Monday, September 14, 2009

GetShare

The previous post inspired me.  How about a function that is a bit more robust?  With this new function you can filter for share names by excluding and/or including specificic text within the share name.  You can even use variables such as * or !.

USAGE
getshare %NAME_OR_IP% [-exclude string, -include string, -csv file]

FUNCTION

function getshare {
  param (
    [string]$name, #Machine to gather shares from
    [string]$exclude, #Text to filter out
    [string]$include, #Text to search for
    [string]$csv #Output to csv
  )
  if ($exclude -and $include) { $list = GWMI win32_share -computer $name | ($_.name -notlike $exclude) -and ($_.name -like $include)} }
  elseif ($exclude) { $list = GWMI win32_share -computer $name | ? {$_.name -notlike $exclude} }
  elseif ($include) { $list = GWMI win32_share -computer $name | ? {$_.name -like $include} }
  else { $list = GWMI win32_share -computer $name }

  if ($csv) { $list | Export-Csv $csv -NoTypeInformation ; Import-Csv $csv | select Name,Path,Description | fl}
  else { $list | fl }
}
 code: copy : expand : collapse

Friday, September 11, 2009

PSPing

So, I decided to play around today and mimic ping.exe in PoSh.  I've created the function below to do just that.  Not all elements are working yet, but its a great start for just a few hours.  Right now its a bit messy, but I'll clean it up in a future post and walk through it as well.

This is great little function to add into your profile.  Not familiar with how to do that?  I'll cover it later.

USAGE
psping %NAME_OR_IP% [-i,-l,-n,-w,-f,-t]

NOTE
Options with the pound (#) in front of the line are not available yet.

function psping {
  param (
    [string]$name, #Machine to ping
    [string]$i, #Time To Live
    #[string]$j, #Loose source route along host-list
    #[string]$k, #Strict source route along host-list
    [string]$l, #Send buffer size
    #[string]$r, #Record route for count hops
    [string]$n, #Number of echo requests to send
    #[string]$s, #Timestamp for count hops
    #[string]$v, #Type Of Service
    [string]$w, #Timeout in millieseonds to wait for each reply
    #[switch]$a, #Resolve address to hostnames
    [switch]$f, #send Don't Fragment flag in packet
    [switch]$t #Ping the specified host until stopped
  )

  $ErrPref = $ErrorActionPreference
  $erroractionpreference = "SilentlyContinue"
  if ($i) { [int]$setTTL = $i } else { [int]$setTTL = 125 }
  if ($l) { [int]$setBufferSize = $l } else { [int]$setBufferSize = 32 }
  if ($n) { $setPingAttempts = $n } else { $setPingAttempts = 4 }
  if ($t) { $setPingAttempts = 0 }
  if ($w) { [int]$setTimeout = $w } else {[int]$setTimeout = 120 }
  if ($f) { [switch]$setDontFragment = $true } else { [switch]$setDontFragment = $false }
  $setOptions = new-object System.Net.NetworkInformation.PingOptions
  $setOptions.TTL = $setTTL
  $setOptions.DontFragment = $setDontFragment
  $setBuffer=([system.text.encoding]::ASCII).getbytes("a"*$setBufferSize)
  $ping = New-Object System.Net.NetworkInformation.Ping
  $reply = $ping.send($name)
  Write-Host ""
  if (!$reply) {
    $msg = "Ping request could not find host " + $name + ". Please check the name and try again."
    $msg
  } elseif ($reply.Status -eq "Success" -or $reply.Status -eq "TimedOut") {
    $fqdn = [system.net.dns]::GetHostEntry($name).HostName
    if ($reply.Address.IPAddressToString -ne $null) { $msg = "Pinging " + $fqdn + " `[" + $reply.Address.IPAddressToString + "`] with " + $l + " bytes of data`:`n" }
    else { $msg = "Pinging " + $fqdn + " with 32 bytes of data`:`n" }
    Write-Host $msg
    $count = 0
    $roundTripMin = 126
    $roundTripMax = 0
    $roundTripCount = 0
    $roundTripAvg = 0
    $received = 0
    do {
      Start-Sleep -seconds 1
      $count += 1
      $reply = $ping.Send($name,$setTimeOut,$setBuffer,$setOptions)
      $ip = $reply.Address.IpAddressToString
      if ($reply.Status -eq "Success") {
        $buffer = $reply.Buffer.Count
        $roundTrip = $reply.RoundtripTime
        $ttl =$reply.Options.Ttl
        $received += 1
        if ($roundTrip -lt $roundTripMin) { $roundTripMin = $roundTrip }
        if ($roundTrip -gt $roundTripMax) { $roundTripMax = $roundTrip }
        $roundTripCount += $roundTrip
        $msg = "Reply from " + $ip + "`: bytes=" + $buffer + " time=" + $roundTrip + " ttl=" + $ttl
      } elseif ($reply.Status -eq "TtlExpired") {
        $msg = "Reply from " + $ip + "`: TTL expired in transit."
      } elseif ($reply.Status -eq "TimedOut") {
      $msg = "Request timed out."
    }
    Write-Host $msg
  } until ( $count -eq $setPingAttempts )
  if ($received -gt 0) {
    $loss = (($count / $received) - 1) * 100
    $roundTripAvg = [Math]::Round(($roundTripCount/$count),2)
  } else {
    $loss =
    $roundTripAvg = 0
  }
  $msg = "
Ping statistics for " + $reply.Address.IpAddressToString + ":
Packets: Sent = " + $count + ", Received = " + $received + ", Loss = " + ($count - $received) + " (" + $loss + "% loss),
Approximate round trip times in milli-seconds:
Minimum = " + $roundTripMin + "ms, Maximum = " + $roundTripMax + "ms, Average = " + $roundTripAvg + "ms"
Write-Host $msg
  } else {
    $reply
  }
  $ErrorActionPreference = $ErrPref
  if ($reply) { rv reply }
  if ($ErrPref) { rv ErrPref }
}
 code: copy : expand : collapse