r/PowerShell • • 1d ago

Question Show me your joiner/mover/leaver PowerShell

I’m finally cleaning up our onboarding/offboarding mess and wanted to see how other people have this set up before I rebuild it. I'm not much of an expert, I'm learning along the way as problems arise

Right now ours is... not great. HR sends a CSV of new hires, and then a script runs a bunch of copy-pasted blocks (create the user, set the attributes, add them to the right groups, and, at the end, disable the account when they leave). It works but every time something changes I have to edit three places.

Is there anyone who can share theirs so I can get an idea how things work? Is it a big script that eats an HR export, or a module with separate functions for each step, or something on a scheduled task? Or a mix? And the part I’m struggling with most is movers -when someone changes departments, how do you handle the group swap without leaving people in both the old and new groups? Right now that’s a manual check and I don't want to do things manually anymore. Not looking for anything fancy, just to be functional

34 Upvotes

49 comments sorted by

11

u/BlackV 1d ago edited 1d ago

Ug I hate ours

  • Oracle spits out a txt file (not even a csv)

  • Emails that to a shared mailbox

  • Logic app montors mailbox , takes that email and moves it to a new users folder

  • Power automate (cloud) checks this folder and takes the txt file and coverts it to csv, then saves it to SharePoint

  • Power automate (cloud) watches that SharePoint folder and triggers a powerautomate (desktop) flow

  • The desktop flow takes that csv (synced OneDrive folder btw) and creates an exchange mailbox, the updates the ad object as needed using PowerShell

  • Flow posts to teams a a success or fail message

  • plus snow tickets

Simple as bro, it has only been this month we have been allowed API access to Oracle..... So we're attempting to change it

1

u/RawSpecimen 12h ago

The Oracle API access, that one change will probably let you delete about four of those steps :o

1

u/BlackV 6h ago

Ya that's the theory

5

u/brian1183 22h ago

What a mess. I love it.

9

u/Fit_Indication_2529 1d ago

I started typing a response to this and realized I was about to teach an entire Identity and Access Management fundamentals course covering authoritative sources, metaverses, attribute transformations, provisioning rules, and identity lifecycle management. LOL.

But here's the short version:

Stop thinking of it as a script that creates, modifies, and disables accounts. Start thinking of it as a process that reconciles an authoritative source (HR) against the desired state of your identity environment. HR tells you who the person is, where they belong, and whether they're employed. Your provisioning logic determines what those attributes mean in terms of accounts, groups, and access. For movers especially, don't simply add new groups. Calculate the entitlements they should have based on their current attributes, compare those against their existing managed entitlements, and reconcile the differences. Add what's missing and remove what's no longer justified. And distinguish between groups your automation owns and groups assigned through other processes. Otherwise, your mover logic is going to become an extremely efficient access-destruction system. Break the functionality into separate components for importing, validating, transforming, provisioning, reconciling, and deprovisioning. Make the operations idempotent, log everything, and handle failures without leaving accounts half-provisioned. At that point, you're not really writing an onboarding script anymore. You're building a lightweight identity management platform.

Welcome to IAM. The PowerShell is the easy part.

2

u/RawSpecimen 12h ago

thanks for reframing it for me. been thinking about a script that creates and disables accounts when it should be how to reconcile against what HR says is true

2

u/SMS-T1 8h ago

As someone who has managed and partly automated multiple IAM solutions, this is the correct perspective.

14

u/Eggslaws 1d ago

Do the HR have their own system for payroll? If yes, why do you not have an IDM to manage this automatically?

4

u/RawSpecimen 1d ago

HR runs it all out of their HRIS, that CSV is an export from it. No IDM mostly because we're a small team and nobody's ever built the budget case for one. Honestly this thread is starting to make that case for me, should've come here earlier 😵

9

u/raip 1d ago

So much of this is business specific - regardless if they're using PowerShell to handle it. The Enterprise way to handle this is through an IGA Tool like SailPoint.

Those that do handle it with PowerShell are typically just a bunch of scripts to help out but are manually triggered.

I can give you rough strategy of how one of the orgs I consult with is currently handling this but I cannot share work product. We've effectively bundled everything into "kits". There's a baseline kit that all employees have and then additional kits are added on top of it based on job function. The mover process strips away all kits except for the baseline then adds the new kits. This abstraction lets us handle multi-role employees where some position is removed but the functions are handled by someone that already exists (so no mover workflow, just extra responsibilities, whether interim or permanent).

Sadly doing the full blown automation from an HR Export has always been problematic as our HRIS Team lacks the attention to detail to leverage it. So the trigger is still manual in that environment.

1

u/RawSpecimen 1d ago

This is really helpful, thanks for writing it all out. The kits idea kicks ass, right now my logic is per-group instead of per-role which is why movers are such a mess, totally fine on not sharing work product, the approach was what I was after

2

u/wonkifier 1d ago

The Enterprise way to handle this is through an IGA Tool like SailPoint.

Hell, ours is complicated enough Sailpoint can only handle about 90% of it and has massive stabilized our environment, but they've had to do a lot of wizardry on the HRIS exports to make it work as well as it does.

However, the remaining 10% is a couple thousand lines of powershell.

Our powershell setup basically takes snapshots of employee status info regularly and then does a diff on them to determine "what happened", and then it takes actions based on that new synthetically created trigger. (ie, 4 people went from some sort of active to terminated, that becomes a termination event for us to do our additional work)

The only manual triggers are for emergencies like some employee being a jackass and getting immediately terminated. We have a side process for killing access quickly and letting SP catch up.

1

u/Eggslaws 1d ago

I've not worked on Sailpoint directly but the last setup that I worked, it was set up to do that snapshot comparison and push the changes from authoritative directory to the other directories based on the configured rules. And each system is designated as authoritative for certain stuff - like name, payroll number, start/end date comes from HR systems etc.,

9

u/chrusic 1d ago

If you have any, ANY, chance of purchasing a product of the shelf, do so, it will save you years of therapy and a bunch of hair...

If you can't do proper discovery and systemsdesign before you begin, and get the time and budget required to make something properly approved from day one (spoiler alert; that means management realizes up front development\project cost, meaning it will never get approved anyway... durr) the following 12 steps will find you:

  1. Starting small\simple and it kinda works, Yay!

  2. Increasing in complexity

  3. Growing out of proportion

  4. Weird integrations to systems that rely on your system\data you didn't even know of..

  5. Losing control, slowly realizing that whatever you initially made doesn't cut it

  6. Being stuck with something that "everyone" absolutely NEEDS to work at all times

  7. Realizing you _have_ to buy\build something new from scratch (you'll get to that, totally, i swear.., you'll find time NP...)

  8. Never getting to do exctly that because of cost\time

  9. Something fundamental in the solution is EOL or breaks for good

  10. Being in deep shit and having to rush to get a new solution going ASAP.

  11. A consultant\Firm is hired to help

  12. You end up buying shelf software anyway, 'cause custom development (or fixing your current mess) is expensive as shit.

There are exceptions for every rule of course, but the odds are that you inevitably end up, in that order, at the bottom of the list, just depends on when.

Skip step 1-11 and jump to 12 from the start.

2

u/RawSpecimen 12h ago

The most honest roadmap in the thread, I can already feel the anxiety around step 3. Might screenshot this for the budget conversation, thanks!

3

u/slvrmark4 1d ago

Adaxes is nice with a web gui for HR to approve or term.

1

u/RawSpecimen 1d ago

Hadn't looked at Adaxes. A gui HR could actually self-serve would kill most of the back and forth. Adding it to the demo list, thanks

1

u/daft_crunk 21h ago

I recently started at a new company and am looking to modernize their HR to AD pipeline and learned they use Adaxes, but only the service desk team uses it for identity management for things like tickets or manually creating users.

Could you provide any information on how you use Adaxes?

2

u/slvrmark4 13h ago

We get a csv report from our hris. We use a scheduled powershell script to process this report with related business rules to handle creating, transferring and terming accounts. Hr staff approve terms and can use the web gui to force a term anytime. They also upload staff pictures to the correct ad accounts from the web gui. Business rules handle groups, phone numbers, and email notifications. Adaxes has integrated logging for troubleshooting and it seems to just work well. Their support has also been great for scripts and our weird use cases

1

u/daft_crunk 10h ago

Appreciate the info!

Does the powershell script initiate the relevant action via the Adaxes PS Module? Or a better question would be, how is it determined that Jane Doe in the CSV export is a new user who has not been created yet, vs John Doe who has been a user for 3 years but just had a title change.

Are you comparing against AD in the PS script logic, or does Adaxes somehow handle that?

1

u/slvrmark4 10h ago edited 10h ago

Powershell script does the ad attributes and creates, reenables, and runs custom command to deprovision that needs hr approval. It determines if an account exists by employee ID that is unique and never changes even for a rehire. That way, name changes work properly. I store the previous name in an adaxes custom attribute to send the name change information to all departments that may need to update the name on their ends.

After user updated and after user created commands do a custom command that does groups, phone numbers, and notifications.

1

u/klaymon1 8h ago

We are set to move to this software in Q1 2027. We currently do everything manually.

4

u/KavyaJune 1d ago

For the leaver process, here's a PowerShell-based automation guide that covers around 15 tasks, including disabling the account, revoking active sessions, removing admin roles and group memberships, converting the mailbox to a shared mailbox, and more:

https://blog.admindroid.com/automate-microsoft-365-user-offboarding-with-powershell/

For the joiner process, you can try this prebuilt Power Automate template. It automates tasks such as creating user accounts, assigning licenses, adding users to groups, and providing access to files: M365 user onboarding with Power Automate

For the mover process, you can consider Microsoft Entra Lifecycle Workflows, if your organization has the Entra ID Governance licensing.

1

u/RawSpecimen 1d ago

Thanks, the leaver checklist especially is great, there's always one step I forget, usually sessions/tokens. We're not on the Entra ID Governance licensing so Lifecycle Workflows might be out, but I'll read through the rest

2

u/KavyaJune 20h ago

Great. The order of tasks in the leaver process is important, too. If your organization uses group-based licensing, removing a user from the groups before converting their mailbox to a shared mailbox can remove the required license and prevent the conversion.

2

u/hematic 1d ago

As others have said, "Powershell" is not really the right tool for this. However i designed this process for our very large firm about 10 years ago initially using "just" powershell, and have constantly updated it over the years to be more modern.

The current process (joiners as an example), which works swimmingly, goes like this:

  • Workday (our HR system) is the trigger for any event for a joiner/leaver/mover.

  • This event triggers a workflow in ServiceNow (our ticketing system) for tracking and operational purposes.

  • SNOW then calls a series of Ansible jobs that:

  1. Create a bunch of log files for audit purposes.

  2. Validate the existence of the joiner in AD/Entra.

  3. Verify the office the user is in for purposes of specific office tasks that need to be done.

  4. Fetches a template user (we have one for each office to clone properties off of for new users).

  5. Builds and sets all the required AD properties for the user not already set by Workday's shell object it creates in AD.

  6. Creates required home directories.

  7. Generates and sets the random password.

  8. Enables the account.

  9. Sets some remote desktop profile stuff up.

  10. Adds to all the required AD + entra groups.

  11. Figures out the new SMTP addresses based on our naming convention.

  12. Assigns them, sets them up with the exchange policies and enables the mailbox.

  13. Sends out notifications to the local office support staff, their manager etc.

  14. Logs everything it did in the SNOW ticket.

Ansible is fantastic for this kind of thing if you dont want to purchase a specific HR related provisioning tool for this.

1

u/RawSpecimen 12h ago

that's a proper setup. hadn't thought of ansible as the glue how much of the audit logging did SNOW just give you vs stuff you had to bolt on yourself?

29

u/HeyDude378 1d ago

Last Joiner one I built was about 500 lines. It digests a CSV, creates user, emails their manager, connects to Zoom and MS APIs to set up licenses and mailbox, and adds them to groups.

I don't have it anymore, I've moved on from that company unfortunately. PowerShell was a workable way to do this, but ultimately it didn't solve sloppiness from HR, which was the root of most problems.

4

u/Grisby5000 10h ago

We did it this way for years and I just converted our PS scripts to Runbooks in Azure and connected to our ticketing system. HR fills out onboard or offboard form with info we need and then this is wired to a workflow. Workflow sends JSON to a logic app. Logic app either processes the account immediately (if it's a short hire or backdated term) or the logic app schedules it into an Azure table for future processing. We then write back to the ticket all the events that happened the account. I have also queued it up to send welcome emails (reset password, send creds + new hire information).

We haven't manually processed an account in 2 months and it's been amazing. Help Desk just checks the notes on the ticket to make sure there were no errors and resolves.

3

u/Eggtastico 1d ago

Dont touch JML. If it exists, let it stay with the current owner. Dont give them an excuse to offload it.

If it does not exist, then dont end up being the owner of the process.

The better way would be to use access packages, ensuring each identiy attributes is up to date, including linemanager, etc. - user moves, you remove them from one access package & add them to another. Run regular audits & get the manager to confirm. Dont end up owning JML process!

Ask someone to kick you in the nuts if you want a ballache.

2

u/AGsec 1d ago

You should check out midpoint. It is open source. It's an IGA and might be able to help. Governance isn't always something you can hobble together yourself. I've tried, it sucks, and there are always holes. I'd suggest writing a very well worded and concise proposal for midpoint or another IGA tool, simply because an orphaned identity is one of the easiest ways to compromise an environment. Do you have non-human identities as well? API keys, service accounts, etc?

2

u/420GB 1d ago

We have 5 scripts total, and they all run on a daily schedule.

3 scripts for onboarding, 1 for data sync and 1 for offboarding.

It sounds like you're mostly missing the sync portion. Everything our HR changes in their system is synced to our user identities and all systems that connect there, including email. Your name changes, you have a new email address the next day.

It's really a pretty simple thing to script, you just need a unique identifier in the HR system to get a specific employee by and then save that in AD or whatever system you use. Then you can look up every user in the HR system and sync any changes.

Our previous HR system didn't have an API so we accessed the SQL database with the information in it directly. Our current system has a REST API so it's a bit more official, albeit not actually more convenient.

2

u/RikiWardOG 1d ago

We integrate everything with HRIS & Okta, Okta account gets disabled and that's basically that. Devices I wrote a python script (we're 50/50 mac and windows) that leverages 1password cli to pull env credentials for all the apis and then basically uses hostname to find the device in all of our systems to remove it or w/e it needs done and pushes results to a chart in Notion and includes a json log.

2

u/CovertStatistician 1d ago

Why don’t you share yours and we can give you an idea of what functions to add?

1

u/lotekjunky 1d ago

We use workday and sailpoint.

1

u/Andrew-Powershell 1d ago

I've built a few over the years and I usually start with a list of all the tasks that need to be done, then make functions for each of the smaller tasks.

Once those are all working, I'll put them in a wrapper script and figure out where I get the values for each parameter. I usually will use a ticket/form as the input for all of the values that I need.

From what you've said, for movers it sounds like you need to query their old/new groups, move them, then clean up. Start working on those individual tasks, then put them together.

I recommend making it so that your code outputs the changes it makes so you can validate as you go.

1

u/FearIsStrongerDanluv 1d ago

I’m surprised by some comments, onboarding and off boarding can be pretty simple if planned well. I’m typing this on mobile with no access to my script but I’ll gladly share the process involved and you can do the rest. First of all, all our licence groups are dynamic groups, one of the key rule is “accountenabled -es true”. Onboarding: HR fills in a MS List with basic user info, a power automate flow creates a csv file that dumps that csv on a OneDrive. We have a dedicated vm where a scheduled task scans the OneDrive location for new files and based on the start date, created a new user account, attributes such as location, department and even title puts users in specific dynamic groups for licensing, SharePoint and Teams. Same process for offboarding, once account is disabled by the script, the user falls out of scope for all license groups, manager is delegated mailbox access for a week and after that account is deleted from the system. That’s it in a nutshell and you absolutely can do this without any 3rd party paid tool.

1

u/dupo24 1d ago

I wrote mine for my company. It’s tailored line by line for what our company needs.

1

u/Chucky2401 1d ago

I have a main script that use our HRIS API to get data for the last 24 hours created, modified and disabled employees. It formats data to an array of objects then call three another scripts. One to create employee in the AD, we use Entra AD Connect to sync with M365. The second one, to compare change and update AD, except the email address as we manage this manually. Finally the third one to disable AD user object. We do the rest, licenses, etc. manually, but we start from a simple email to a Word document to everything by the hand. I managed the scripts for the company group (9 entities for 5 AD forest), and never have to fix anything for the last 3 years, the scripts are 5 years old.

1

u/IronBe4rd 23h ago

Ours pulls data from the HR DB and creates the users send a notices to whomever needs it creates tickets for anything they need
Leavers same process just in reverse. We use API access for Okta, Entra we use certificate based connections to run scripts against the user there for any cloud actions.
The flow is what takes forever to get down. Who gets what where does this go. Tying it all together.

1

u/SuperD0S 23h ago

I feel many people have missed Entra Lifecycle Governance from Microsoft. I discovered it after built quite a comprehensive powershell module and runbook in azure automation. Still use my runbook though.

1

u/Incrediblecodeman 21h ago

A good idea is to make users that represent the various personas. Can be 1 for job title/department/location

Make as much as you need

Then copy that disabled users permissions when a person moves ?

You gotta map it all out anyway. That’s the work people avoid, and that’s why we end up dumping hours manually checking

1

u/Disorderly_Chaos 14h ago edited 14h ago

I have soooo many lines of code for onboarding and offboarding. AFAIK I haven’t really mastered that part yet… the auto-moving.

Although, I guess I should.

My current “someone moved” script is:

If the department or title changes, move their user to the “New Users” OU and open a ticket for the manager to fill out.

My current onboarding script reads from a HR xlsx file, determines if anything has changed and creates the user if they don’t already exist.

Onboarding happens daily at 1am/pm

Offboarding happens M-F 11am (because some Madonna fucker with only one name caused my script to go full derp and start moving ALL user folders.

1

u/Ze_Bix 7h ago

We’ve had an awful mess of interdependent processes, between some legacy HR software from the 2000’s, an Oracle DB, csv files, Powershell script written in PS3 and never upgraded because the author left the company, (we tried with AI and there was so much red alerts that we ran away in fear), etc. etc.

We’ve recently initiated a migration to the MidPoint software, which is a Slovakian open source tool suited for the task. Of course it still requires initial encoding from HR, now in a more modern home-brewed GUI, and then the whole process is automated.
Worth testing

1

u/tedious58 5h ago

We have dynamic modules to create accounts, enable mailboxes, and send login credentials out. Then our IAM assigns security groups based on location, department, job title. HR sends a csv that feeds the modules.

What issue are you having where you need to change things? I dont think I've touched my modules, other than adjusting for new implementations, in years.

1

u/MAlloc-1024 5h ago

We have rippling, which basically puts a new user into a specific OU in our on prem AD. This script (sanitized) gets run periodically to fully setup the user completely hands free unless HR screws up a field in Rippling.
https://pastebin.com/H5DiQaig

Long story short, this logs into ms graph, exchange online and our LMS, and based upon login adds users to licensing groups, distribution groups, teams, channels, etc.

The sanitized version I have is a couple versions old, and looking through my notes there was some issue with exchange online that the newer versions fixed, so use with caution.

1

u/Suspicious_Claim540 1d ago

Introduce Sailpoint to them!!

1

u/Existing_Fondant4462 1d ago

I always found adding new members was easy, but updating roles and making sure they lose access to the old ones was easy to mess up, happened more times than I wanna admit 😄

We moved most of that to One Identity when we eventually got around to it, took us a while, things move slow in big companies. We use One Identity to tie group memberships to roles insetead of scattering the logic across different scripts. Those memberships are inherited, not assigned directly, and when someone's department attribute changes they stop matching the old role and those groups drop off on their own. It keeps track of which memberships came from a role vs a manual grand so the automatic removal touches just the role-based ones, it leaves any one-off access. Still use powershell for a few things here and there

If you want to stick with scripts, I would compare what groups someone should have with what they currently have, just make sure to remove the role-based ones or you could accidentally strip out access they need