LAPS WinForm 2

New and improved LAPS WinForm because the original one, found here, was kind of crap. It didn’t handle exceptions very well and I don’t think the group policy update worked at all after some further debugging.

I am please to present the new GUI for LAPS:

The best place to download this from would be my TechNet gallery

Enjoy!

Linux Directory Checking Script

Morning! Oh wait, it’s the afternoon…

Today, I finally got around to making a script that will run automatically on my network storage server (Raspberry Pi with a dinky USB hard drive) and check if the USB HDD is accessible.

This issue started a couple of weeks ago where I was getting weird IO errors on the USB disk about every 2 weeks. Instead of buying a new drive, creating a RAID array or anything else equally as intelligent and appropriate, I decided to just reboot my Raspberry Pi every time this happened. Now, I don’t want to do this manually every time so I finally created a script and added it to my cron jobs.

You can see the script I used below:

#!/bin/bash

if [ ! -d "path/to/check" ]; then
    #Directory is not found and HDD is not okay, do whatever is below
    uptime=$(uptime)
    currenttime=$(date)
    echo "Host rebooted at $currenttime. Uptime was$uptime" >> /path/to/output.txt
    sudo reboot
fi

My crontab job is running as root because the sudo reboot part was giving me a couple of issues. This is the entry in the root crontab:

@hourly /path/to/sh/file

Enjoy!

SharePoint Group Membership WinForm

This is a little WinForm I created that would output the group membership for a domain user or FBA (Forms-Based Authentication) user on SharePoint.

This is what the form looks like, it gives the option for a domain or FBA user and also checked if the user exists before trying to get the relevant information:

The form first checks if CredSSP is configured on your machine to delegate your credentials to the SharePoint server. The form then loads, waits for your input, validates your input and finally collects the group information for your input.

And finally, this is the code for the Winform. I’ve removed some details as they need to be filled in by you. Enjoy!

#CHECKING CREDSSP SETTINGS
if ((Get-Item  WSMan:\localhost\Client\Auth\CredSSP).value -eq $false){
    #CREDSSP NOT CONFIGURED, EXITING
    Write-Host @"
    
CredSSP is not configured!

Please open an elavated PowerShell prompt and run:

Enable-WSManCredSSP -Role client -DelegateComputer sandsharepointf

"@
    Exit
}else{}

#LOADING ASSEMBLIES
Add-Type -AssemblyName System.Windows.Forms
[System.Windows.Forms.Application]::EnableVisualStyles()

#ICON FOR THE FORM
[string]$icon64=@"
#base64data
"@

#CONVERTING BASE 64 ICON INTO GRAPHIC
$iconstream = [System.IO.MemoryStream][System.Convert]::FromBase64String($icon64)
$iconbmp = [System.Drawing.Bitmap][System.Drawing.Image]::FromStream($iconstream)
$iconhandle = $iconbmp.GetHicon()
$icon = [System.Drawing.Icon]::FromHandle($iconhandle)

#FORM
$SharePoint_Membership_Form                 = New-Object system.Windows.Forms.Form
$SharePoint_Membership_Form.ClientSize      = '400,278'
$SharePoint_Membership_Form.text            = "SharePoint Membership"
$SharePoint_Membership_Form.TopMost         = $false
$SharePoint_Membership_Form.StartPosition   = "centerscreen"
$SharePoint_Membership_Form.Icon            = $icon
$SharePoint_Membership_Form.FormBorderStyle = "Fixed3D"

#USERNAME LABEL
$Username_Label                  = New-Object system.Windows.Forms.Label
$Username_Label.text             = "Enter a username:"
$Username_Label.AutoSize         = $true
$Username_Label.width            = 25
$Username_Label.height           = 10
$Username_Label.location         = New-Object System.Drawing.Point(146,12)

#USERNAME TEXTBOX
$Username_Textbox                = New-Object system.Windows.Forms.TextBox
$Username_Textbox.multiline      = $false
$Username_Textbox.width          = 175
$Username_Textbox.height         = 20
$Username_Textbox.location       = New-Object System.Drawing.Point(115,33)

#VARIABLE FOR KEYDOWN
$Username_Textbox_keydown = {}

#KEYDOWN ASSIGNED
$Username_Textbox_keydown = [System.Windows.Forms.KeyEventHandler]{
    if ($_.keycode -eq 'Enter'){
        $Search_Button.PerformClick()
    }
}

#REGISTER KEYDOWN HANDLER TO USERNAME TEXTBOX
$Username_Textbox.add_keydown($Username_Textbox_keydown)

#DOMAIN RADIO BUTTON
$Domain_User_RB                  = New-Object system.Windows.Forms.RadioButton
$Domain_User_RB.text             = "Domain User"
$Domain_User_RB.AutoSize         = $true
$Domain_User_RB.width            = 104
$Domain_User_RB.height           = 20
$Domain_User_RB.location         = New-Object System.Drawing.Point(120,64)
$Domain_User_RB.Checked          = $true

#SHAREPOINT FBA USER RADIO BUTTON
$FBA_User_RB                     = New-Object system.Windows.Forms.RadioButton
$FBA_User_RB.text                = "FBA User"
$FBA_User_RB.AutoSize            = $true
$FBA_User_RB.width               = 104
$FBA_User_RB.height              = 20
$FBA_User_RB.location            = New-Object System.Drawing.Point(215,64)

#SEARCH BUTTON
$Search_Button                  = New-Object system.Windows.Forms.Button
$Search_Button.text             = "Search"
$Search_Button.width            = 60
$Search_Button.height           = 30
$Search_Button.location         = New-Object System.Drawing.Point(171,89)

#SEPERATOR LINE
$Seperator_Label                 = New-Object system.Windows.Forms.Label
$Seperator_Label.text            = ""
$Seperator_Label.AutoSize        = $false
$Seperator_Label.BorderStyle     = "Fixed3D"
$Seperator_Label.width           = 390
$Seperator_Label.height          = 2
$Seperator_Label.location        = New-Object System.Drawing.Point(5,124)

#OUTPUT TEXTBOX
$Output_Textbox                 = New-Object System.Windows.Forms.TextBox
$Output_Textbox.Multiline       = $true
$Output_Textbox.Width           = 390
$Output_Textbox.Height          = 142
$Output_Textbox.Location        = New-Object System.Drawing.Point(5,131)
$Output_Textbox.ReadOnly        = $true
$Output_Textbox.ScrollBars      = "vertical"

#ADDING CONTROLS TO FORM
$SharePoint_Membership_Form.controls.AddRange(@($Domain_User_RB,$FBA_User_RB,$Seperator_Label,$Username_Label,$Username_Textbox,$Search_Button,$Output_Textbox))

$Search_Button.add_click({

    $Output_Textbox.Text = ""

    #DATE FOR OUTPUT
    $date = Get-Date    
    $username_value = $Username_Textbox.Text
    $Username_Prefix = $null
    $location = #base location

    #SETTING SEARCH VALUES BACK TO FALSE
    $Search_On_AD_User = $false
    $Search_On_FBA_User = $false

    #CHECKING IF USERNAME TEXTBOX IS EMPTY
    if ($Username_Textbox.Text.Length -le 0){
        #IF EMPTY, VARIABLE IS FALSE
        $Output_Textbox.AppendText("$date - $Username cannot be empty! `n")
        $Username_Not_Empty = $false
    }else{
        $Username_Not_Empty = $true
        $Output_Textbox.Text = ""
    }

    #RUNS IF DOMAIN USER RADIO BUTTON IS CHECKED
    if ($Domain_User_RB.Checked -and $Username_Not_Empty){
        try{
            $Output_Textbox.AppendText("$date - Searching for $username_value `n")
            Get-ADUser -Identity $username_value

            $Output_Textbox.AppendText("$date - Found user! `n")

            $Search_On_AD_User = $true
            $Search_On_FBA_User = $false

            $Username_Found = $true

        }catch{
            $Output_Textbox.AppendText("$date - Cannot find domain user `n")
            $Username_Found = $false
        }
    }

    #RUNS IF FBA USER RADIO BUTTON IS CHECKED
    if ($FBA_User_RB.Checked -and $Username_Not_Empty){
        
        $SPAdmin = "sharepoint_admin_user"
        $credential = New-Object System.Management.Automation.PSCredential $SPAdmin,  (Get-Content "$location\sharepoint_admin_user_encrypted_password.txt" | ConvertTo-SecureString )

        $sb = {
            $username = $args[0]
            Add-PSSnapin microsoft.sharepoint.PowerShell
            $user = Get-SPUser -Limit All -Web http://SHAREPOINTSERVER | 
                Where-Object {$_.loginname -like "i:0#.f|fbamembershipprovider|$username"}

            return $user
        }

        $Output_Textbox.AppendText("$date - Trying to find $username_value... `n")

        $invokeoutputfbasearch = Invoke-Command -ScriptBlock $sb -ComputerName SHAREPOINTSERVER -Authentication Credssp -Credential $credential -ArgumentList $username_value

        if ($invokeoutputfbasearch){
            #FOUND USER
            $Username_Found = $true
            $Search_On_FBA_User = $true
            $Search_On_AD_User = $false
            $Output_Textbox.AppendText("$date - Found FBA user!`n")
        }else{
            #NOT FOUND USER
            $Username_Found = $false
            $Output_Textbox.AppendText("$date - Cannot find FBA user `n")
        }
    }

    #ONLY RUNS IF BELOW CONDITIONS ARE MET
    if ($Username_Found -and $Username_Not_Empty){
        #ASSIGNING THE RIGHT USERNAME FORMAT
        if ($Search_On_AD_User){
            $Username_Prefix = "*|DOMAIN_NAME\"
        }else{
            $Username_Prefix = "i:0#.f|fbamembershipprovider|"
        }

        $SPAdmin = "sharepoint_admin_user"
        $credential = New-Object System.Management.Automation.PSCredential $SPAdmin,  (Get-Content "$location\sharepoint_admin_user_encrypted_password.txt" | ConvertTo-SecureString )

        $sb = { 
            $groups = $null
            $prefix = $args[0]
            $username = $args[1]
            Add-PSSnapin Microsoft.SharePoint.PowerShell
            $user = get-SPUser -limit all -web http://SHAREPOINTSERVER | 
                Where-Object { $_.loginname -like "$prefix$username" }
                $SPGroups = get-spsite -limit all | 
                    Select-Object -ExpandProperty rootweb | 
                    Select-Object -ExpandProperty siteusers | 
                    Where-Object { $user.userlogin -eq $_.loginname } | 
                    Select-Object -ExpandProperty groups | 
                    Select-Object -ExpandProperty name
            foreach ($i in $SPGroups){
                $groups = $groups + "     - $i `r`n"
            }
        return $groups
        }

        $Output_Textbox.AppendText("$date - Collecting group info on $username_value... `n")

        $InvokeOutputfinal = Invoke-Command -ScriptBlock $sb -ComputerName SHAREPOINTSERVER -Authentication Credssp -Credential $credential -ArgumentList $Username_Prefix,$username_value

        $Output_Textbox.AppendText("`n")
        $Output_Textbox.AppendText("$InvokeOutputfinal")

    }else{#THIS SERVES ONLY AS A TRAP TO STOP ANYTHING RUNNING
    }
})

#DISPLAYING FORM
[void]$SharePoint_Membership_Form.ShowDialog()

Using DinoPass in PowerShell

This is a nice little trick I learnt whilst automating domain user creation with PowerShell, I found generating passwords in PowerShell was always ugly. Just see the example below from a previous post I’d made:

[string]$initialpassword = ([char[]](Get-Random -input $(47..57 + 65..90 +97..122) -count 8)) + (Get-Random -minimum 0 -maximum 10)

$passwordwithspacesremoved = $initialpassword.Replace(' ','')

$convertedpassword = ConvertTo-SecureString -AsPlainText $passwordwithspacesremoved -Force

This would generate a password like “cDUtxlvM5” which is just about as ugly as the code used to create it.

So I decided to use DinoPass instead since it created better looking passwords without the faff of generating them in PowerShell. This is a the code I used:

Invoke-WebRequest -Uri https://www.dinopass.com/password/strong | Select-Object -ExpandProperty content

Which would give me a much nicer, but still secure, password like “poorJump62”. Then to use it when automating domain user creation, I would use the below and put the whole thing into a variable that I would set the password to:

$super_secure_password = Invoke-WebRequest -Uri https://www.dinopass.com/password/strong | Select-Object -ExpandProperty content | ConvertTo-SecureString -AsPlainText -Force

Enjoy!

Blackjack in PowerShell

This is a little function that mimics a simplified version of blackjack. I have wrapped it in a function for cleanliness and so that it can be called again.

The rules are below:

  • Get a higher total than the dealer
  • Keep your total under 21 or you will be bust
  • That’s it

Here is the code for you to try this out yourself, hope you enjoy!

function blackjack{

    #CHANGING NAME OF WINDOW
    $pshost = Get-Host
    $pswindow = $pshost.UI.RawUI
    $pswindow.WindowTitle = "Blackjack" 

    #RESETTING GAME OVER VARIABLE
    $blackjack_game_over = $false

    #GENERATING A RANDOM TOTAL FOR THE DEALER
    $blackjack_dealer_total = Get-Random -Minimum 14 -Maximum 22

    #CREATING AN ARRAY FOR THE USERS CARD NUMBERS
    $blackjack_user_card_array = [System.Collections.ArrayList]::new("")

    #GENERATING A RANDOM NUMBER FOR THE USERS FIRST CARD
    $blackjack_user_first_card = Get-Random -Minimum 1 -Maximum 11

    #ADDING USERS FIRST CARD TO ARRAY
    $blackjack_user_card_array.Add($blackjack_user_first_card)

    #CREATING A VARIABLE TO COUNT USERS TOTAL
    $blackjack_user_total = $blackjack_user_first_card

    Clear-Host

    Write-Host "Your first card is $blackjack_user_first_card"

    #DO THIS (PLAY GAME) UNTIL THE GAMEOVER VARIABLE IS TRUE
    do {
        #GET USER INPUT
        do {$blackjack_input = Read-Host "Take another card? (Y or N)"}while (("y","n") -notcontains $blackjack_input)

        #IF USER INPUT IS VALID AND ISN'T BUST AND WANTS ANOTHER CARD
        if ($blackjack_input -eq "y" -and $blackjack_user_total -le 21){

            #GENERATE A NEW CARD FOR THE USER
            $blackjack_user_new_card = Get-Random -Minimum 1 -Maximum 11

            #ADD NEW CARD TO CARD ARRAY
            $blackjack_user_card_array.Add($blackjack_user_new_card)

            #ADD NEW CARD TO CARD TOTAL
            $blackjack_user_total = $blackjack_user_total + $blackjack_user_new_card

            Clear-Host

            Write-Host "You have $blackjack_user_card_array"

            #IF THE USER IS BUST
            if ($blackjack_user_total -gt 21){
                Write-Host "You went bust! The dealer won with " -ForegroundColor Red -NoNewline
                Write-Host $blackjack_dealer_total 
                $blackjack_game_over = $true
            }
            
        #IF THE USER DOESNT WANT ANOTHER CARD
        }else{

            Clear-Host
            
            #OUTPUTTING THE FINAL SCORE
            #Write-Host "You had $blackjack_user_total and the dealer had $blackjack_dealer_total"

            #SWITCH TO SEE WHO WON
            switch ($blackjack_user_total){
                {$_ -gt 21}{Write-Host "You went bust! The dealer won with " -ForegroundColor Red -NoNewline; Write-Host $blackjack_dealer_total; $blackjack_game_over = $true; break}
                {$_ -eq $blackjack_dealer_total}{Write-Host "It's a draw, the dealer also had $blackjack_dealer_total"; $blackjack_game_over = $true; break}
                {$_ -gt $blackjack_dealer_total}{Write-Host "You win! The dealer only had " -ForegroundColor Green -NoNewline; Write-Host $blackjack_dealer_total; $blackjack_game_over = $true; break}
                {$_ -lt $blackjack_dealer_total}{Write-Host "You lose! The dealer won with " -ForegroundColor Red -NoNewline; Write-Host $blackjack_dealer_total; $blackjack_game_over = $true; break}
                default {Write-Host "Something happeneds that wasn't accounted for!" -ForegroundColor Red; break}
            }
        }
    }until ($blackjack_game_over)

    #ASK USER IF THEY WANT TO REPLAY UNTIL INPUT IS A Y OR N
    do {$blackjack_play_again = Read-Host "Do you want to play again? Y or N"} while (("y","n") -notcontains $blackjack_play_again)

    #SWITCH TO EITHER PLAY AGAIN OR GO TO MAIN MENU
    switch ($blackjack_play_again){
        "y" {blackjack}
        "n" {exit}
        default {exit}
    }   
}