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.
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.
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.
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;
Create a similar GPO (disabled) alternatively use the production GPO (the one that someones dad created, aka DADGPO (tm) )
Backup this GPO to a safe(er) area (not sysvol)
Commit XML edits to change the desired condition
Create a new Blank GPO
Use Import-GPO’s ID parameter, and input the edited GPO
Link the GPO to desired new OU
(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.
Group name (DelegationGrouo) of the AD group you want to edit within the GPO settings
Domain name in case of multi-domain forest
Takes the input, and outputs a new GPO with the updated AD Group provided:
functionNew-AdminPolicyGPO{param($Name,$DelegationGroup,$Domain)Begin{# Insert whatever validation checks you needif(Get-GPO$Name-ErrorActionSilentlyContinue){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 variableNew-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-PathBackUpPath}else{New-Item-Path$BackUpPath-ItemTypeDirectory$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 XMLSet-Content$SuperLongAndFunString-Value$xml-VerboseImport-GPO-BackupId$BackedupGPO.Id-Path$BackedupGPO.BackupDirectory-TargetName$GPO.DisplayName}catch{$Error[0]Break}}else{Break#Can't locate GPO from backup}}}
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.
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.
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.
This is my attempt at creating my own password generator
functionGet-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/lowerif($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 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:
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:
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
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:
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.
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.
“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.
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
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!
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.
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!
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.
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.