PowerShell for Automation: Simple Hyper-V VM-Creation script

Meet Labmil.

Labmil is a script I made to serve a specific usecase. When AutomatedLab is overkill, and when you don’t want to skip the installation phase of the lab.

Displaying the cmdlet

Features

  • Quickly put the Windows Server ISO-file to good use
  • It’s a simple script for anyone to modify for personal needs
  • It outputs a customobject
  • Create multiple VM’s using PowerShell logic

Non-Features

The script has a few non-features. Non-Features are cool because it makes the script unique and useful in certain senarios.

  • Not touching the VMs application layer makes it simple and less prone to error
  • It only has two parameters, and only one of them is mandatory after initial run, adding simplicity
  • It enables you as an sysadmin/engineer to do the whole set-up. Giving you more work to do yourself, meaning more labbing!
  • It’s only focus is Hyper-V VMs

How I like to do my labs

  1. Spin up the VMs you plan on labbing with using New-LabmilVM.ps1
  2. Install the server with wanted settings and partitions
  3. Use Windows Terminal’s split-tab functionallity, together with
Enter-PSSession -VMName $Name

To have one tab open with each newly created Lab-VM.

Happy labbing!

PowerShell Solution: Automate GPO creations

The headache of setting up recurring GPO’s

I was faced with an issue not too long ago, and I spent quite some time trying to come up with an @automated solution to the problem. I thought that some hypothetical sysadmin might find themselves in a similar situation in the future, and this might save the hypothetical person some time.

The problem I was trying to solve was the following; How do we script the task of creating a new GPO with the same base settings but with different conditions (Strings (AD Groups, Hostnames), IP’s, true/false), in an automated fasion?

The best answer to this question is; You probably shouldn’t.

If the GPO planning is done carefully, you should not find yourself having this problem - since why would we want 10-100-1000 different GPOs doing basically the same thing? If we could use WMI filters, script-based, logically acting GPOs, the world would be a wonderful place.

Reality hits you hard, bro

Let’s be real, you either did the GPO planning yourself back in the 90’s, or someones (probably awesome) dad did it. And he probably had a tight schedule, IT was probably understaffed already back then, and frankly, all companies might not have a Mark Russinovich-kind of guy, implementing flawless, scalable GPO plans for your organization.

Sadly the facts listed above does not help you in any way what so ever. Hopefully the rest of this blog post can.

Technical bits

PowerShell and GPO’s go quite nicly hand in hand, thankfully. Now starts the technical fun stuff. The following is what we need to solve:

Have a script that allows you to input a specific condition (City name, Group name, Computer name, yada yada), and have this script:

  • Create a New GPO

  • Set the specific GPO settings you need

  • Link the GPO to the specific OU(s)

But how? GPO’s are all XML and you really need GPMC to get the exact settings right, and I would rather not edit XML files in SYSVOL, what if I mess something up?

I’m glad you asked! Here’s the kicker:

Since we’re trying to automate the creation of a recurring GPO, there’s already a GPO in place that does almost the exact thing you need. All we need to do is;

  1. Create a similar GPO (disabled) alternatively use the production GPO (the one that someones dad created, aka DADGPO (tm) )

  2. Backup this GPO to a safe(er) area (not sysvol)

  3. Commit XML edits to change the desired condition

  4. Create a new Blank GPO

  5. Use Import-GPO’s ID parameter, and input the edited GPO

  6. Link the GPO to desired new OU

  7. (optional) Be excited and tell everyone that you’ve just automated a process of EDITING AND CREATING new GPOs

This process solves two big issues, firstly it allows you to just edit the recurring GPO once, this would otherwise be a recurring task.

Secondly, it solves the issue with editing GPO’s in production, since you should’t tamper with XML files in a production sysvol. Instead the edits you do are directly done to the backup file that’s outside of sysvol.

Let us see some code already

This function lets you input

  1. Name of the new GPO

  2. Group name (DelegationGrouo) of the AD group you want to edit within the GPO settings

  3. Domain name in case of multi-domain forest

Takes the input, and outputs a new GPO with the updated AD Group provided:

function New-AdminPolicyGPO {
    param (
        $Name,
        $DelegationGroup,
        $Domain
    )
    Begin {

        # Insert whatever validation checks you need

        if (Get-GPO $Name -ErrorAction SilentlyContinue) {
            Write-Warning "GPO already exists"
            Break
        }
    
        if (Get-ADGroup $DelegationGroup) {
            $DelegationGroup = Get-ADGroup $DelegationGroup
        }
        else {
            Write-Warning "ADGroup not identified"
            Break
        }
    

    }
    Process {
    
    <#
        RootGPOs GUID needs to be changed to the DADGPO guid
        An easy way of getting GUID is to just run: 
        Get-GPO -All | ? DisplayName -Like "Name of gpo"
    #>

        $RootGPO = Get-GPO -Guid "D4DGP0-GU1D-D4DGP0-GU1D-D4DGP0-GU1D"

        # Create blank GPO and store it in a variable
        New-GPO $Name
        $GPO = Get-GPO $Name


        #Create path for backup gpo
        $BackUpPath = "$env:LOCALAPPDATA\BackupGPO\"
        if (Test-Path $BackUpPath) {
            $BackedupGPO = Backup-GPO -Guid $RootGPO.Guid -Path BackUpPath
        }
        else {
            New-Item -Path $BackUpPath -ItemType Directory
            $BackedupGPO = Backup-GPO -Guid $RootGPO.Guid -Path $BackUpPath
        }

        #Store XML file of backup gpo in variable
        $SuperLongAndFunString = "$BackUpPath{$($BackedupGPO.ID.GUID)}\DomainSysvol\gpo\Machine\Preferences\Groups\Groups.xml"
        if (Test-Path $SuperLongAndFunString) {
            try {
                # Play around with this part until Set-Content
                # changes the desired GPO setting

                $xml = Get-Content $SuperLongAndFunString

                $xml = $xml.Replace('"Domain\ADGroupName" action="ADD" sid="Whatever the SID is"', """$Domain\$
                ($DelegationGroup.Name)"" action=$('"ADD"') sid=""$($DelegationGroup.sid)""" ) #Edit XML
                
                Set-Content $SuperLongAndFunString -Value $xml -Verbose
                
                Import-GPO -BackupId $BackedupGPO.Id -Path $BackedupGPO.BackupDirectory -TargetName $GPO.DisplayName
            }
            catch {
                $Error[0]
                Break
            }
        }
        else {
            Break #Can't locate GPO from backup
        }
    }
}

Lastly

This function serves as a base for you to use, and the point here is really to demonstrate the process of how you could tackle this problem. I would suggest playing around with get/set-content to get the desired outcome of the GPO settings in a lab env before even thinking about implementation to production.

In many cases, GPO setting changes are XML changes. PowerShell lets you configure anything within an XML file. The key to doing so is to understand the specific setting, so you can manipulate the backed up GPO’s XML in your favor.

Happy coding

/Emil

PowerShell for Security: PassWord Gen Part 1

My history with Password Generators

Password generators can be very simple and fun to build, and I thought that publishing my own history with creating them can be a good source of knowledge for other people, hence this post :)

My first version of Get-GeneratedPassword was created in Powershell 3.0, and at that point I didn’t have that many requirements, the usecase for the function was basically to stash it in my $profile to quickly set new passwords for various AD accounts.

However the first version was based on a dotnet class method called: [System.Web.Security.Membership]::GeneratePassword

Adam Bertram does a great job covering how to wrap this in a module, click the class name to read his post about it.

The class does bring a dependency on the the specific dotnet class, and for me, this approach started to bring errors in Powershell cores early versions.

New attempt without dependencies

This is my attempt at creating my own password generator

function Get-GeneratedPassword {
<#
.SYNOPSIS
    Cross-platform password generator
.DESCRIPTION
    Get-GeneratedPassword is using a Get-Random, a string and regex 
    validation to ensure that the password meets the complexity level 
    enforced by default in ActiveDirectory
.EXAMPLE
    PS C:\> Get-GeneratedPassword -PwLength 10 -Amount 10
    Generates 10 passwords with the length set to 10
.EXAMPLE
    PS C:\> Get-GeneratedPassword -PwLength 12 | clip
    Only supported in Windows. Will generate a password with 12 as length 
    and clip the result to clipboard
.EXAMPLE
    PS C:\> $user = "emil"; $pw = ConvertTo-SecureString -String (Get-GeneratedPassword 12) -AsPlainText
    PS C:\> $creds = $user,$pw
    Creates a CredentialObject that can be passed in to user generating cmdlets
.EXAMPLE
    PS C:\> Get-GeneratedPassword -PwLength 8 -Amount 100 | Out-File C:\Temp\PW.txt
    Generates 100 passwords to a textfile stored in C:\Temp\PW.txt
.INPUTS
    PwLengt as int32
.OUTPUTS
    Outputs randomized password as string(s)
.NOTES
    Purpose :   Designed to meet AD Complexity rules & be crossplatform (Windows, Linux)
    Author  :   Emil.t.Larsson@gmail.com
    Date    :   2021-05-11
    OS      :   Win10, Ubuntu 20
    Version :   1.0.0
#>
    [CmdletBinding()]
    Param
    (
        
        [Parameter(Mandatory = $true,
            ValueFromPipelineByPropertyName = $true,
            Position = 0)]
        [ValidateRange(6, 30)]
        [int32]$PwLength,
        [Parameter(Mandatory = $false)]
        [int32]$Amount = 1
    )

    Begin {
        $Password = @()
    }
    Process {

        $PwdValues = "-!@#$%^&*_{}()?0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz"

        do {

            $PasswordGenerated = ($PwdValues.ToCharArray() | Sort-Object { Get-Random })[1..$PwLength] -join ''

            # Regex rules, contains any of the special AND 0-9 AND upper/lower
            if (
                $PasswordGenerated -match "[-!@#$%^&*_{}()?]" -and 
                $PasswordGenerated -match "(?-i)[A-Z]" -and 
                $PasswordGenerated -match "(?-i)[a-z]" -and 
                $PasswordGenerated -match "[0-9]"
            ) {
                # Add to pw array
                $Password += $PasswordGenerated
            }
            else {
                Continue
            }
        }
        until ($Password.count -eq $Amount)
    }
    End {
        $Password
    }
}

The script can be found on my GitHub PS repo

Displaying the cmdlet

Read the comment based help, or load the function and run:

Get-Help Get-GeneratedPassword

My Requirements was the following

  • Cover AD complexity rules (in 99,9%)
  • String output, for simplicity
  • X-platform
  • No dependencies outside of Powershell 7

Begin

The function starts of by enforcing some of the requirements using ValidateRange, and a default value for the -Amount parameter
[ValidateRange(6, 30)] [int32]$PwLength

Since AD’s complexity rule is enforcing at least 6 chars, this range checks that requirement box.

[int32]$Amount = 1

The default value solves the issue of just running the cmdlet without the -Amount parameter

Next up is the whole idea behind the script, instead of using a dotnet class, I’ll just generate my own string of chars to pick from:

$pwdvalues = "-!@#$%^&*_{}()?0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz"

By using a do-until loop, I can simply abuse Get-Random:
$PasswordGenerated = ($pwdvalues.tochararray() | Sort-Object { Get-Random })[1..$PwLength] -join ''

until my desired count of complex passwords are achieved by validating them through some regex validations:

$PasswordGenerated -match "[-!@#$%^&*_{}()?]" -and

$PasswordGenerated -match "(?-i)[A-Z]" -and

$PasswordGenerated -match "(?-i)[a-z]" -and

$PasswordGenerated -match "[0-9]"

This validation is critical for only getting the complex passwords for output

The “(?-i)” part is needed since PowerShell by default is case-insensitive, this definition solves that part, and we need this since we really do care about the match being case-sensitive. This blog post by Jake Bolton covers the problem in detail.

Since all we do here is randomly grabbing strings and joining them, we’re only working with a string object. Making the script fast and the output very simple, and since the output is just a simple string, it can be easily turned into a .txt file or used within ConvertTo-SecureString

Lastly

This is a quite simple and short function, and I’m sure it wont cover all my password generating needs for the future, but hopefully for some time at least.

I hope this post got you thinking & curious about:

  • regex validation
  • do-while loops
  • string manipulation
  • case sensitivity
  • self-made functions

in Powershell!

Happy coding

/Emil

PowerShell Solution: Script not digitally signed

“.ps1 is not digitally signed. The script will not execute on the system.”

This error is clearly not really a typical error, but can be a blocker, nonetheless. It’s more of a security feature than an error.

Simple solution if you’re running this script from another service, or as an Azure Runbook, before executing the Invoke-Command:

Set-ExecutionPolicy -Scope Process -ExecutionPolicy Bypass

This will allow the powershell session process itself to bypass the Exec policy, and after termination the next powershell process has the default user or system policy.

Another solution would be if you’re executing the script from your own user:

Set-ExecutionPolicy RemoteSigned

Further documentation regarding Set-ExecutionPolicy may be found here.

Original blogpost that helped me solve this issue was found here: here.

Happy coding

Book review: Life 3.0

Life 3.0, Being human in the age of AI

Life 3.0 by Max Tegmark

Life 3.0 by Max Tegmark – Life 3.0 At Amazon

First book on AI

Personally, this was the first time reading a book about AI. And as a tech-savvy sysadmin who loves video games, sci-fi and great stories, it got me hooked.

It’s author, Max Tegmark, got me very interested in the subject and he does so by being naturally curious, super-nerdy in a fun way, and just all-round knowledgeable in tech, he’s a professor after all!

The book starts off with a scenario (the Omega team) that could’ve been a Hollywood movie plot, and as well a real-life situation. The description on the treat of AI is very clear: It’s not the “Terminator” style AI that’s threatening, It’s AIs built with goals that do not align with the human civilization.

Goals

“The more intelligent and powerful machines get, the more important it becomes that their goals are aligned with ours. As long as we build only relatively dumb machines, the question isn’t whether human goals will prevail in the end, but merely how much trouble these machines can cause humanity before we figure out how to solve the goal-alignment problem.”

  • Making AI understand our goal.

  • Making AI adopt our goals.

  • Making AI retain our goals.

I think this is one of the biggest take-aways of the book, and if I would’ve been a AI/deep-learning developer, I’d take this very serious in my line of work.

Myths

The book covers a few well-known AI myths as well as some facts regarding them, I’d figure that it would be good to list a few of them in this review since I found them both interesting and helpful in understanding what the actual AI problems and concerns are, not only what’s being rumored about or displayed in cinema:

  • Superintelligence by 2100 is inevitable. Fact: Experts disagree & simply does not know

  • Only Luddites worry about AI. Fact: Many top AI researchers are concerned

  • Robots are the main concern. Fact: Misaligned intelligence is the main concern: it needs no body, only an internet connection

  • AI can’t control humans. Fact: Intelligence enables control: we control tigers by being smarter

  • Machines can’t have goals. Fact: A heat-seeking missile has a goal

Closing words

In general, the book is not as “heavy” as you would expect coming from a super-brain like Tegmark, it’s in-depth and detailed, but in an interesting and curious way.

I would not recommend this book if you’re not interested in the subject, but if you are, it’s a great entry point.

I’ve read a few books on AI now, some of them are listed in the “up and coming” section of the blog, but I must say that Max Tegmark is probably the more pedagogical AI-book author then many others, and to that I am grateful.

I recommend reading this book if your interested in the subject of AI!

Book Review: LOTR, The Fellowship of the Ring

LOTR: The Fellowship of the Ring

LOTR: The Fellowship of the Ring – At Amazon

One ring to rule them all, one Ring to find them*

One Ring to bring them all and in the darkness bind them

Sometimes when I read books, I get a feeling to just read faster, not pay attention to detail, to get to the point of the story. While reading Lord of the rings, I forgot about that feeling completely.

I think this says a lot about Tolkien’s ability to pay attention to detail, details that forges the story deeper and deeper the more you read, it’s addictive.

To compare this book with its prequel ‘The Hobbit’ is rather difficult, for the following reason: The book is not made for children, and it’s very refreshing to step into a darker and deeper side of middle earth, even the farmers of the Shire are somewhat scary for the adventurers.

There are complete chapters of the book that will be a new story for readers that’ve watched the movies, and that fact alone is reason enough for you to pick it up and read the hell out of it! Because that’s what you’ll probably find yourself doing, binge read it, it’s that good.

Character details

Frodo is a completely different character compared to the movies, and for the better. And there’s so many lessons of life that Sam teaches throughout the book, about being humble, faithful, and a good friend.

Another favorite character of mine is Elrond. The references he does to the elder days, he’s basically a living history book – paying attention Elrond, to be curious about his character, will tell a lot about the history of middle earth between the lines, about the 1st and 2nd age, the War of Wrath and history of the first children of Ilúvatar.

Boromir’s inner demons, fighting what’s right and wrong, fighting with valor within the fellowship, but being weak-minded and ensnared by the ring, is in my mind a timeless tale of how important it is with mindset, being humble, and how a constant seek for glory is doomed to fail in the long run.

I deeply love this book, if you couldn’t tell already, and would of course highly recommend it to you!

Book Review: The Hobbit

The Hobbit

The Hobbit – At Amazon

“A timeless advanture for all ages”

This book was surprisingly easy to read, and it’s in my opinion light-years better than the movies. I read the entire book in Swedish, and although it’s only been a year since I read it, I already have an urge to re-read the whole book in English. The translations just don’t cut it for someone who’s interested in the lore of middle earth.
Although this book is less heavy on lore, and more focused on the telling of a great adventure.

A recommendation

From me would be, if you read the book to your child, the translated version is fine, but if you plan on reading the Hobbit for your own amusement, read the English version.

I plan to read this book for my children, and hopefully they’ll get hooked on Tolkien’s world, just like I did by reading The Hobbit.

My favorite part of the book must be the whole meeting between Bilbo and Gollum. Tolkien’s style of writing is just mesmerizing, and even though you know that Bilbo is probably not going to get murdered, you can’t help it to be on edge throughout most of the chapter.

I will revisit this review once I’ve read it in English, the translations are a bit fuzzy still, but till then I highly recommend reading The Hobbit to anyone having a slight interest in fantasy.