Integration • 53:18
Gain inspiration--and practical advice--from pragmatic Mac OS X system administrators who use Python, Scripting Bridge, Automator, AppleScript, Ruby and other technologies to automate their world, speed repetitive tasks and build highly useful tools.
Speakers: Andy Leeper, Chris Adams, Josh Wisenbaker
Unlisted on Apple Developer site
Downloads from Apple
Transcript
This transcript was generated using Whisper, it has known transcription errors. We are working on an improved version.
This is year number five for Scripting for System Administrators. And I must admit, I said last year we're running out of ideas. It was hard, but we have some very, very good stuff. I beat an engineer into submission until he learned Ruby in seven days. Let that be a lesson to anyone wanting to do this next year.
But Andy did a great job, so we have him coming up here. Chris comes up second, talks about kicking the kicker. And we have a little contest at the end. We need a name for this script, so he'll be talking about that a little bit. And then we follow up with Josh, who wrote a little script just to use the word injector.
So we have a home injector script that you can use at login to do some stuff. So hopefully, get you guys energized, excited about scripting. Show you some new stuff, some of the cool stuff, using Leopard and some of the other technologies. For the first time this year--and I'm very excited about this because we've been trying it for a while but never got anything to stick--Chris will be talking about some of the scripting bridges.
So how to go from your scripts to actual Objective-C and things like that. To add a little more power and to kind of combine both of those worlds. So, without further ado, I'd like to introduce Andy Leeper. He's going to come up here and talk to you about some Ruby.
Hello, everybody. I'm here to talk about Ruby. And I'm actually going to do that by giving you my story of how I did this. So if you like a lot of caffeine, this is great. If you just so happen to be one of those people that likes to learn scripting languages in their free time, this is a good way to go through and kind of jump start that whole thing. So let's go ahead and jump in.
On the first day, what happened was Joel gave me a buzz and he said, "Hey, Andy, I'd really like you to come speak at WWDC this year." And I was thinking to myself, "Oh, yes, you know, of course. Like, why wouldn't I want to? This is a great opportunity.
I get to get in front of all you guys and talk to everybody and, you know, it would be awesome." And he said, "Well, it would be in our scripting for sysadmin session." And, you know, I had come for the past four years, you said it was, five years, and, you know, I thought it was a really cool session. I was--I felt honored.
So I jumped into it and I had just the tool I wanted to show you. And I had a tool that my coworker wrote called Ghost Host which takes information from Open Directory, puts it into a MySQL database and kind of uses some augmented data to kind of bring all this together into a nice user interface. So I said, "Hey, you know, he developed this thing in three or four weeks. I can come up and talk about that. You know, it might be really interesting to some folks." And, you know, Joel liked it.
And I said, "Hey, you know, Joel liked the idea." But he came back to me and said, "Hey, you know, you wrote this all in PHP. Can you do it in Ruby?" And I was thinking to myself, "Ugh." I don't know. One of my friends at work is a big Ruby evangelist, and he sits there and he talks about, man, you can write everything in two lines of code. You don't have to do anything. In fact, I wrote this wonderful application that does the same thing in like seven lines of code. So I was a little skeptical, so I went and did my own research.
And you know, I went to Google. I typed in Ruby. And the first thing that I got was this website, which is the ruby-lang.org website. So some of the things you'll see over on the right-hand side is the Try Ruby in your web browser. That brings you to this page. And this is a really useful tool for just checking it out on your own time. It kind of hand-holds you through it.
And it was a really useful resource for me. So I went through the first chapter. And when I went through the first chapter, I realized that, you know, this is how I do something in Perl. This is how I do something in Ruby, you know, as far as declaring my variables. Not all that different.
So I said, "Hey Joel, you know what, I'd be honored to go ahead and do this. I thought it would be a great opportunity." So I jumped right in. So the next day... Yeah, I go to work. I work hard like everybody else. I put in my 10, 15 hours.
And when I get home from work, I want to play games. I don't really want to, like, do more work, right? Well, I realized, no, I should probably be a good engineer. I should spend some time and get back onto the Ruby thing. So I pulled open Safari. I searched for Ruby again because I forgot what website I went to.
And I wound up at the same website. Fortunately, it's the first Google link, so I didn't have to do much crawling. And I went back to the tutorial. And this time, I went through chapters 1 through 5. So chapters 1 through 5 kind of uncovered a little bit more stuff. It uncovered stuff like control structures. So in Perl, this is how you do a for each loop to go through an array. And in Ruby, it's not so similar. You end up doing stuff like things.each do thing.
And I wound up at the same website. Fortunately, it's the first Google link, so I didn't have to do much crawling. And I went back to the tutorial. And this time, I went through chapters 1 through 5. It looks nothing like Perl. So I figured, well, the concept's still the same.
I can still apply what I know about scripting into learning this new thing. So I decided, well, hey, I'm just going to make a list. So what are some things that I typically use? I typically use variables, I typically use loops, and I typically use functions like everybody else. And so I decided to map it out between Perl and between Ruby.
So the next day. I go into work, do my normal routine, drink some coffee, type some email, you know, do the normal thing there. I got an email that said, "Hey, your code is due in five days for review." I was a little bit panicked. I was--no. I don't really have much together. I thought I was going to have a couple weeks to present this thing. I have five days to put this thing together. Oh, I probably shouldn't have played World of Warcraft last night. Not a good idea.
It's really intimidating to learn a foreign language. By the way, I threw this in here because it's a little side joke to those who do know Ruby. The creator of Ruby is Japanese. But it's really intimidating to learn a new foreign language. But I realized that, hey, as long as I remain methodical about it and I plan everything out, it should still come out okay. So I started off with the basics. This is how you do Hello World in Ruby. Not all that different from Perl.
You just use a different command. Actually, you can still use print if you wanted to. This is how you do arrays. Still really basic. Actually, to those of you who know Python, it's pretty close to the Python syntax. And I also found some other stuff along the way such as, hey, there are methods to call on these things because everything inside of Ruby is an object.
So you get some free stuff. This is much easier than it is in Perl. So, I got so fascinated with the stuff that I was learning when I was going through this that I stayed up until like 3 in the morning playing on it and it was just fun. And I fell asleep on my keyboard.
It's not fun to wake up to beep beep beep beep beep beep beep, you know, that's going on on your computer, so. The next day was Saturday. and I'm here with Andy. I'm going to talk about the first step of the code development process. I'm going to talk about the first step of the code development process. I'm going to talk about the first step of the code development process. I'm going to talk about the first step of the code development process.
I'm a real person. I really do like to have my free time. I really do like to play games. So I did some gaming, but then I decided at noon, oh, no, I really need to jump into it. And one of the things I wanted to tackle was how do I get this thing to talk into open directory because this is kind of what I need to develop. I'm sure that there's code that's already done for me here. So I found this thing called Ruby Gems. This is a box of gems that does--it's kind of a package manager for Ruby. So it's like CPAN for Perl or like eggs for Python. Ruby has gems.
and I found a module called Ruby Net LDAP. And what that let me do is it let me, first off, take a lot of their example code to get my program to talk to Open Directory. But it was not--it was not all that hard to get my script up and going based off the example code. I just tweaked the server name and I tweaked, you know, a couple of the things here and there to get what I wanted out of it. And by 10:00 that night, I had something that was working. I was talking to Open Directory.
I was getting information out. It was working fine. I was parsing it in the way that I wanted it to be parsed. And everything is kosher. And I think the reason why I was able to get to that point was because I stopped, I listed everything out, I was methodical and I broke the problem down into smaller chunks. So when you're learning a new language, do the same thing that you do in the other So the next day involves Rails.
So I wanted to get a jump start on it. Unfortunately, I had slept because I was exhausted from all this coding. And I woke up a little bit later. And I had my script that was spitting out, you know, stuff like this. It was giving me the IP address out of open directory. It was giving me the host name out of open directory.
I had a little ping function that would see if it was up or down. And I wanted to convert this into something that was a little bit more snazzy and put a nice little web interface on it. I wanted it to be like this program. So somebody at work had been evangelizing Ruby on Rails to me.
And they said, "Oh, yeah, Rails is the way to get all your code and put it up on the web and takes five lines of code." Same Ruby evangelist guy. And so I started to do some searching. And I came upon the site, which is the rubyonrails.org website.
One of the things that was really useful here was the screencast. And people talk much faster than I do through these screencasts. But it shows how you can build a completely full--a fully functional application that talks to Flickr and does all sorts of crazy stuff. It's really inspirational.
And one thing that's nice is OS X has all the stuff built into the system. So I didn't have to go download and install Rails or anything. It's all built into Leopard out of the box. So for me to get a basic website up, I just had to type in these three things. And you get your basic start page. It's not all that exciting.
So I figured out, oh, I'm just going to follow the next two steps, or two lines of code, to get this thing to generate a template for me to use. These are kind of what you would use. And what's nice is on OS X Leopard, all this stuff automatically creates the SQLite database for you to use, and it does all this other stuff for you magically.
and you get a really basic website. So this doesn't look anything like the other page that I wanted. I wanted to figure out how I can get my code into this and to have it all formatted all nice and pretty and to make it presentable. And I ended up bashing my head into the wall trying to make this work. And I think the biggest reason why is because I was trying to write stuff procedurally, and it doesn't work that way with Rails.
So I found that out by going into Freenode on IRC and wanted to pound Ruby on Rails. The people there are really useful. There's a topic on the channel that pointed me to this really useful Ruby on Rails documentation website called noobkit.com. Very appropriate for me. And it was all interactive, showed a lot of examples, but I still didn't really get it and I went to sleep.
I just kind of gave up. But on the next day, I went into I figured, hey, I'm going to talk to my Ruby evangelist friend because he said it would be five lines of code. I did my five lines on the terminal and it's not doing it. So I talked to him a little bit about what problems I was running up against. And he went on a spiel about the Rails way.
So the Rails way, what is that? Well, in all the sessions at WWDC, we've been talking about model, view, controller. The Rails way means using a model, a view, and a controller for your program. I was trying to write everything procedural. I was trying to generate all my stuff.
I had my view mixed in with my logic and all this other stuff. And it wasn't working. And after talking to him about that, he kind of said, oh, yeah, no, it's very much like Objective-C. So I know that you played around with it a little bit. Just kind of do it that way.
So I did. And I was thinking, oh, wow, OK, that makes a lot more sense. I don't know why it wasn't obvious to me before, probably because of the amount of caffeine I've been having. But I went home and decided, hey, I'm going to jump right in, I'm going to jump into the terminal, get hacking away.
And I realized that the solution to my problem was kind of staring me in the face. I already had the SQLite database that is housing all of my supplemental information, like I was doing with my PHP thing. And I realized that there's an additional piece of functionality that's built into Ruby on Rails, which is Rake. And I could just leverage those two technologies to get what I wanted. And the last day came. And I want to show you what I was able to put together.
So if we can go to--hey, please. So let's pull up my website here. I was able to get it going. This is all in Ruby on Rails. So some nice things here is this lets you see information from open directory that you might find. So like your host name, your IP address. I did the DNS resolution by generating that information.
Mac address I was able to get out of there. The owner information was stuff that I put in. The location was stuff I put in. Serial number I put in. When the record was created, it was done in Open Directory. So I was able to merge these sets of information together. My Rake script that I'm running runs every minute and it tells me whether or not a server is up and down. This is all--this didn't take less--more than a week to put together.
You can click on this stuff, you can go through and edit stuff. So I can say Pacific Heights, X-Motion, X-Motion, update. And it goes through and it updates it all on the back end and this is all nice and dandy. Obviously this is fake information or else I'd do a little bit more of a detailed demo, but... I want to jump into the code that I used to put this together. I hope this is big enough for everybody way back there. This is showing the view for the web page. So you'll notice it's just a--it looks like normal HTML.
and down here there's more normal HTML. You'll see that I have some extra stuff embedded in here. This shows off the templating style that Ruby gives you--or Ruby on Rails gives you rather--which lets you go through and inject Ruby code into your HTML. So this is my view. This is what makes up the lovely page here. The model part--I'm sorry, the controller part is over here.
This is saying whenever you go to the index page, I'm going to find all the stuff that's inside of your database and I'm going to go through and print it out. So the controller is pretty basic. and the model is all default, so there's no point in showing that. But one thing I do want to show you is where most of the stuff--where the magic is actually happening.
It's inside of this lib task section. And this lib task section is where you can put these things called rake files, which are very much like make files, but this is the component that goes through--and I have this run nightly out of a cron. I just say rake update db and it goes through and updates the database with new hosts out of it. And inside of here, you'll see that there's the server name, LDAP port, all this other kind of stuff.
All it does is it does a search for everything inside of a certain container, grabs it all and puts it inside of the database. I'm not going to dive too much into this because this is pretty much all sample code that you can get out of the Ruby net LDAP documentation.
And then for updating the status, if stuff is online or offline, I have this check host script that runs on a, you know, Mac OS X system. And then I have this check host script that runs on a, you know, minute basis. And all it does is it goes through and it gets all the records out of it where there's an IP address and it pings them.
So I was able to put all this stuff together pretty quickly. Let's go ahead and go back to slides real quick. I was able to put all this stuff together in less than a week with a lot of procrastination, you know, playing video games and stuff. And I think it's a really good story of how, you know, even if you're busy, you're overloaded, you have all this other stuff to do, you can still do it.
It's just a matter of being methodical about it. These are the resources that I used to make myself successful. The rubylang.org website was great for getting started. The interactive tutorial that they had on there was great. That's what made me say yes to begin with. The noobkit.com website was wonderful for the Ruby on Rails documentation.
And the rubyonrails.org website was great for evangelizing, you know, all the different things that you can do with Rails. And RubyForge was where I found out about the net LDAP website. So these are really good resources to use. The people on IRC were so friendly. It's kind of a grab bag sometimes.
But the people on these channels were great. They were really friendly, super accommodating. And the last thing on here, rdoc and ri, that's the online documentation that comes with Ruby. So it's all built into the systems. And with that, I'd like to go ahead and hand it off to Chris who's going to talk talk about kicking the kicker.
So I wanted to talk about the Bridge support that is a very handy feature in 10.5, but since the goal here is to actually solve problems that we face as System Administrators, we're going to do that in the context of building a replacement for the Kicker feature which disappeared in 10.5.
So the much lamented Kicker. So the real underlying goal here though is actually explaining how this is a very nice way for us to interact with the system. Now, our systems that we deal with these days are very complicated and we need to actually do things with that.
We have to restart things or edit policy when the network changes. Perhaps we have something where our users may be mounting volumes. They plug in a FireWire drive and we need to help them pull the video that they've been working on off for an archival project because they're making 20,000 videos and we don't want this to take a week doing it by hand.
There's also a fair amount of time where we need to detect conditions. So we can do something like restart a service which has problems with network transitions or some other policy decision. And the problem that we run into is that the traditional approach for this is to create something like a shell script. Maybe we come up with something where we watch on a log file or run something out of cron every minute or in the worst case give our user something and say, when it breaks, run this and it should hopefully be unbroken.
The problem there is that this doesn't really work that well. You set up your tail and you watch grep for things out of syslog. And then a point release comes out and you find out that somebody at Apple helpfully added more information into the log message, which is great because now your logs convey useful information that you wanted to have except that you've got to go update your regular expression and push that out to all the machines. And that gets old.
What we're trying to do here is get out of this business of being a maintenance programmer, where we have to watch because we're consuming things that weren't really intended for our usage there. We're dealing with things like syslog that wasn't a reliable interface. We have things like running jobs out of cron, where we have to deal with the fact that our job has to run every minute and it has no state. And it means that our scripts tend to be somewhat useless there.
We have these 30 or 40 lines of code there, and exactly four of those actually solve the problem that we wanted. In this case, restarting auto-mount whenever it started hanging, which was a problem in our environment prior to 10.5. And that's a lot of code for us to maintain. In this case, if you look all the way up at the top, you can see it uses the file tail module, which is not stable. We had to install that on some of the machines that needed it.
This approach doesn't scale for the kind of complicated systems that we tend to be building these days. And a lot of the needs that have been coming up are the kind where the conventional approach is becoming less and less suitable for that. Shell languages are not particularly advanced. And now we need to do complicated string processing.
We need to deal with other things like LDAP servers or databases. We might have to parse an XML file or a P list. And then we run into the other major problem for a system administrator is that a lot of the software we use wasn't designed with us in mind. So we have to do something like script GUI events or reverse engineer a configuration file.
I think the answer is for us to go ahead and rethink exactly how we're going about running our systems there. So if we started to ask that question, what would we really want? Well, the answer is clear. We want to become first class users of our systems. When we have problems that we need to solve, we want to solve it the same way that the engineers at Apple or the software development company might solve it using defined APIs, things which were designed for that task so that they don't break. So that we don't run into the little list of caveats to go with things.
In short, we want it to become more like software engineering where we actually are having time to think about things like performance, robustness, usability there, which is really getting past the idea that every problem should be solved with a couple of lines of shell scripting, which I think is a good thing. In this case here, this is an example of the Scripting Bridge framework code.
And it's actually quite interesting. It's a little bit more complicated than the other code. But what we're trying to do here is we're trying to get people to understand the process of how we're going to run our systems. And that's really what we're trying to do here. And we're trying to get people to understand the process of how we're going to run our systems.
using the native API. This is the big change that 10.5 gave us, is now on every Mac we have a standard interface for accessing the Cocoa APIs from a language such as Python or Ruby there. The frameworks will actually handle translating native Python or Ruby variables into whatever the Objective-C API is expecting.
And I realize that this is a somewhat controversial issue, but I find that the resulting Python code is frequently cleaner than the Objective-C code just because the dynamic languages tend to have a very rich syntax, and we can take advantage of that without having to get into the conventional software distribution process and worrying about shipping out 32 and 64-bit binaries and so forth. So the major advantage here is the access that we get to things like the system configuration framework. We can load things like QuickTime.
We can load things like the command line argument parsing so your users get something a little less hostile. It's pretty easy. Rich logging there, which is a system administrators, we demand all of our vendors produce good logging so we have an idea what their processes are doing. Well, we can do the same thing as well.
So this is an example of the fairly minor differences between Objective-C and Python for most of what I'm showing here. You can see it's largely syntax. And in the examples that I worked with there, most of the time I was able to take an Objective-C example out of Apple's device and then I was able to take an Objective-C example out of a developer site, copy it into a text editor, change a few brackets, add an underscore, and run it, and it worked out of the box there. It's a pretty easy process there.
And there is some good documentation available. The last part I think here is the key one, namely that if you have a Mac with the developer tools, you already have most of this code on there, everything from simple command line scripts up to things involving WebKit or complicated GUIs. So it's very much worth looking at.
I did run into a couple of issues which I wanted to point out. The main one just being the understanding that you are, in fact, now becoming a Cocoa programmer if you go down this route. So you have to understand that you're not pure Python anymore. In this case, it was an issue with RunWhoops. It was fairly easy to solve, but I found that this was well worth the time investment.
And then the other point here is you can build GUI applications. There's actually a deprecated example in the developer tools, but it's better just to start with the Xcode template there. Now, actually, earlier in the week, I was at the Cocoa Heads talk, and they mentioned that there's actually an application there which you can go find on the shelf at most Apple stores called Checkout, which is written entirely in Python using the Objective-C bridge. The developer actually was saying that there wasn't a single line of Objective-C code in that application. So this is something that can be used in production.
Also, take a second for a little bit of Python advocacy here. The situation is similar with Ruby, but basically if you're a system administrator, you want to know about at least the modules listed here and then look through the rich standard library out there because again, many of the problems that we need to deal with and the sorts of things that can take a great deal of time in a shell script are already done. So, at that point, let's go back to the kicker discussion here.
Kickr existed because the people at Apple working on OS X had the same needs that we do for dealing with changes. So they needed to be able to run code when the network changed, when the power state changed, the active user changed. And the problem was that this was done in the system configuration framework with an XML file.
Now, if you're already thinking about this, you're going, "Wait, doesn't that live under /system?" And that's the problem. Kickr wasn't a supported feature. It was the easiest way to have something run when an event fired off. But unfortunately, it disappeared completely in 10.5 when they changed some of the structure. We were no longer able to piggyback on that code.
There are also a few other things that we can look at. Kickr was handy for what it was, but frequently we also run into cases where we might want to handle other sorts of events. FSEvents allows us to just monitor arbitrary file system activity in a very low overhead fashion.
This is the same thing that tools like Spotlight use. And it's really handy if you do have some sort of complicated workflow where you need to be able to react to users creating files there. You get an efficient notification, and you can process it directly in your Python code, the same as any other event. Workspace notifications are also handy.
Those apply any time things like a disk image or a network volume is mounted, the active user changes, an application launches. And there's one other improvement that we can make here, which is that we can make this something that doesn't require running as root. This actually means that we can open this up to being a user accessible tool where some of our users, many of mine are scientists who have these complicated workflow requirements, which they're never really going to get quite set in stone because their experiments change.
And so I don't want to give them root on the system, but I also don't want to have to be restarting things and vetting their code all the time. Now they can just run it under their account, and I can just help them out if they get stuck.
I also took the opportunity to take advantage of the logging features and add a few things like being able to list the sort of events that you can monitor on a system so that you can do a little bit of discovery if you're trying to see what sort of tool you can solve. This example is a very simple one here. It uses the network change event just to tell Squid to reconfigure itself. There's--Squid's kind of handy if you're doing web development, but unfortunately it doesn't handle network migration particularly gracefully.
And as you can see here, there's basically one line saying which key we want and we run a single command. And in the example below, you can see that when the network state changes, that fires off and I didn't have to do anything more than that from the perspective of solving Now, we're about to switch to the second and more interesting demo.
But this one, to provide a little background there, OpenSSH has a dynamic proxy mode. When you run that, it will pretend to be a SOC server and tunnel any request over to the remote end of its connection there. So, since we have launchd available, I can have that set up to maintain that SSH connection.
It will restart it if it happens to time out. And then, with the public key agent support in 10.5, I can be sure that my SSH agent is going to be up if I have a network connection. So, the only thing left here is going into my system preferences and checking the little box that says use SOCs. And then, poof, I'm on a conference wireless network. It's secure. I'm off at a place that has some sort of weird ad injection. No problem. Except that I don't want to use it at work because there we have a gigabit network and I don't want the overhead.
And so, the solution here was basically to have a little bit of code which can go in and selectively enable or disable the use of the proxy based on whether or not I'm remote. And can we switch to the demo computer? So, as you can see, currently we have the SOX proxy disabled. There's absolutely nothing set.
Now, unfortunately, the network people here don't want us reconfiguring things, so this is actually a rigged demo, but it's rigged in a way that illustrates how powerful this idea is, because instead of having this triggered by firing off a network change event, I'm going to trigger it by mounting a disk image. And as soon as that runs, You can see that this is updated. Down here we can see the log messages. And if we run the SCUtil, we can see that that's already updated there.
Now the configuration for this is pretty simple. You can see up here I'm looking for an NSWorkspace event. And it's the did mount notification and it just points to a Python class that I wrote. Down here you can see the part which would fire the same event and call the same code if the network configuration changed. There's the entire class, the key part being right here, where it looks to see-- Am I on the corporate network? And if so, go ahead and enable the proxy. So we can switch back to slides.
[Transcript missing]
Thanks Chris. Hey everybody, how are you doing today? We're going to take a look here at something called Home Injector. And unlike the last two speakers who got up there and talked about the death of Shell, I did this in Bash because it was quick, dirty and easy.
So the goal we had in mind here was we wanted to allow users to use portable home directories. For those of you that don't know, just really fast here, portable home directories are very cool. We can use this to take a user that has both a local home and a network home and we synchronize the two.
They're synchronized so if they make a change to the local home, it's synchronized up to the network. If they make a change to the network, it goes the other way. The newest file wins and then you have everything in one place all the time. That way when you leave the office, you have the stuff on your laptop and when you come back to use your big eight core machine, you have everything there as well.
It solves issues with applications that hate network homes. Everybody that has tried to run network homes in an organization has found at least one or two things that just cannot tolerate network homes and this gets rid of that issue as well because you then just have a local home. It works with open directory obviously as an Apple technology.
But honestly more important for most of my customers these days, it works with active directory because active directory is very, very prevalent in the enterprise workspace. So we need to be able to share we work with active directory as well. The syncing is all client side kind of function so the client just needs to know where to go to get the data and put the data.
The key to portable home directories is they need a couple things. They have to have a mobile or an external account. These are exactly the same in Leopard. You can take a laptop with a mobile account on it and put it in target disk mode and instantly it's an external account. The only difference between a mobile account and an external account is that the external account isn't in /users.
Need to have a network home location, obviously, otherwise there's nothing to sync to. This is going to be embedded in the user's account in the directory services. And you need to have a local home location. Again, obviously, if you don't have a local home, you have nothing to sync.
[Transcript missing]
So the solution to this, obviously, is a script. Otherwise I'm in the wrong room. So we need to replicate the logic of a logon script. So we're going to need to take this and we need to figure out how to turn that VB script or .bat file or whatever the heck it is that they're running into something that a Mac can understand. We need to check for group membership. Apple has some very nice tools built specifically to do this. We also need to set the home accordingly.
So there's a couple of issues with this. The first one is where do you get the script? A lot of times the guy who maintains these scripts is maintaining this giant script because he doesn't want to have to do something else or realize that if they just filled in the profile he is no longer needed. But a lot of times they're also kind of shut-ins. They're often a cube somewhere in a basement room and they like someone to come talk to them. So just go ask.
If you just go ask a lot of times, they'll just give you the script and then you can take a look at it and start converting that over to whatever language you want. The other one is how do you set up a portable home account to work? To set up the portable home account to work, we need attributes. What attributes? How do we construct these? Where do we put them? Things like that.
Another way to get that script, which I actually forgot to mention, is that remember I said that Windows machines typically just mount a share and go get the script. Look at a Windows machine that's logging in, see what share it mounts, just go to your Mac then and connect to server SMB colon, whack, whack. Just go download the script straight to your machine as well. I've done that a couple times as well.
So the attributes that we need we came up with are going to be built by HomeInjector.bash. And HomeInjector.bash does a couple things. And this is going to look really similar to the logon script. It runs it log in instead of it log on. It checks for group memberships. It's going to inject the needed attributes and construct those attributes into the user's cached account.
And it turns out you only need two attributes to make all this work. You need SMB home and you need original home location. If you have these two attributes, you can add them to any mobile account, whether that account has a network home defined for it in it or not, and all of a sudden portable home syncing magically works.
So the actual script--and we're going to go through this step by step here, and then we'll do a quick demo with it actually working. So first we need to establish some variables we use. And this is the part where if you consider yourself A Bash expert. You should look away from the screen. I showed this to a friend of mine from Google earlier today and his head literally nearly separated from his shoulders as he just stared gape mouth at this code.
Mainly the group array there where I win the award for the most creative use of the strings command to generate a Bash array. We just have a couple things we need to do. We need to go ahead and figure out what we're going to have. For this example, I use kids and parents because that's always easy.
You put in what the UNC path will be and what the SMB path will be. The UNC path is usually what it will find in the AD profile. The URL is what the AD plugin would generally generate then in order to use this. So there we've got Gannon for the kids. It's our SMB server. Our link server was a Mac OS X server in this case. SMB on both platforms. We're just going to go ahead and use that.
The next thing we need to do is check for group membership. So when you're doing a login hook, login hook has a couple of special variables you can call. $1 in this case is the username of the-- the name of the user logging in. So this way we can just say I'm checking for groups for this person.
And we go back to my cunningly crafted array and we go back and we use DSEditGroup to go ahead and check for the members in there. This is just a built-in function of DSEditGroup. It's been around since Tiger and it's very easy--allows you just to return a good answer. Is this person in this group? If we do find it, then we go ahead and just say yes.
So that's the group they're found in. Obviously if you're doing this on a much larger scale where someone could be in multiple groups, you'd have to write that logic into this. But like I said, this is a proof of concept script so just so you can get the idea of what we're doing here.
We're then going to build out these attributes, which is extremely easy. It's just substituting in some-- the variables we set up. So if they're in kids, then set the kids URL path and the kids SMB path into these attributes here. When I do scripting, if I'm going to have an attribute or something like that that I need to inject, I just name the variable whatever the actual name of what I'm going to be using is. In this case, the attribute SMBHome will be created from the variable SMBHome. It makes it very simple when you're writing your script to keep up with what you're doing.
And then I'm going to inject these into the local directory services and exit. So I just use "discal," I just use "discal local," and in that user, I create these two attributes. You can see again I'm using the $1 there, so I don't have to think about anything. So login hooks will take care of that. And then we just exit out of that cleanly. So I'm going to switch over to the demo machine now.
And we'll take a look at this. Okay. So I have here a Windows 2008 domain controller. And if I were to log in on it, I'll show you I have a user. This machine is bound to Active Directory, but I don't currently have any users set up. Oh, I do have that one. I'm going to remove him real fast.
and David Leith at home. Okay, now we're ready. So if I look in here and I open up ADUC, We can take a look at Owen's account here. And you'll notice that Owen does not have a network home set. So, profile, nothing set. In Active Directory, you can have the local home or the network home. And in this case, there's just nothing to find at all, so we won't have to have it worry about anything. We can look at what he's a member of. He is a member of a group called Windows Homes.
And there he is in there. And that way we know that when we-- that's the group we're going to key off his home folders on a Windows server. So if I cancel out of that and then I log out of this workstation, getting control of my mouse back, we can log in as Owen. So I'm going to log out, leave my domain controller up and running.
I'll log in as Owen. And I've set the AD plugin--and I'll show you these settings in a second-- I've set the AD plugin to just go ahead and make a mobile account and to not bother the user with it. Because inevitably someone checks the wrong box there and then you have to go get the box back for them.
So you can see his home is just a local home here. And if he was to go into the system preferences and look at the account preferences, You'll notice that he has the mobile account here, but it's grayed out. I can't click on it, so I can't set up mobile home syncing or anything like that.
[Transcript missing]
Now that I've authenticated, I can click on Preferences. And I want to set this preference at a machine level. So I'm going to pick my machine here. And here's my bug.
That's a known issue and it is being fixed. It's completely cosmetic issue. It does not affect anything from actually functioning. So if I come in here to scripts and I click on always, here you see I can have login scripts and logout scripts done with policy. Rather than push out the login script to every machine with ARD or something like that, I can just put it in the directory, which is kind of the whole point of using a directory service, and all the workstations then get their script from here.
That way if I find a typo, if I need to make an edit to it or something like that, I don't have to worry about it. I just change it in WorkRoute Manager and all the workstations get it automatically. So I do want to manage the login script, so I put this in a convenient location here to load it in.
Click Open. That loads that into the directory after I clear some dialogs. And now it's ready to go. If I were to look at this, it actually stores that. It encodes it. So it's a little bit scary to look at.
[Transcript missing]
and David So already there was some machine specific MCX attached to this. Now, to get that to work, obviously a login hook--I have to login, right? So I'm going to log out.
and log back in as Owen. And when I do that, all of a sudden my home syncing should be functioning properly. So I'm going to log back in as Owen. To the user, there's no actual change in the behavior that they're seeing. So we get all logged back in.
And now I'm going to open up System Preferences. And magically the button now works. So if I click on Settings here, I can actually go in and set this up. I'm going to say Automatically Sync My Home Folder. And I'll give you my status up there so I can see what I'm doing.
and I'm going to sync the home now. This is following the local sync settings that are default on the client. You could push down more sync settings though using Workgroup Manager and Policy. So it's going to take a second here to do this. It is mounting a home to itself in a Windows VM running on a mini. So this will take a second. So now the home has synchronized and if I were to make a folder here, Demo is working. Then we log out of OWEN. It'll synchronize again here.
And then we'll log back in and we'll actually just look at the file system in Windows and we should see that it's complete. It did work earlier in the lab downstairs, so I'm assuming it's going to work again. And you can actually do this to inject that in so that that sort of thing works. This is because I had synchronized before. The network is newer in this case.
There we go. Because the network is newer, because I just created this mobile account. So as soon as this is done syncing, we'll log back in and we'll take a look and you'll see that it actually did work and I never had to change the AD profile for the user at all. All right. So synchronizing is now complete and we can take a look at that file system.
So if I go back to my VM now, take a look in the console, take a look at the computer. Oh, not that drive. What could they sort them alphabetically now? Holmes, Owen, Desktop. and David So you can see it actually did synchronize the changes back up there. And if we go back and look at Owen's account still, again just to verify that there is no home path set. So we can go back to the slides now.
So a couple things to keep in mind about this. I can see some gears around the room grinding in minds right now because I'm sure there's someone in this room that is stuck with these antiquated Windows logon policies to determine network homes. So the real solution is not to script this at all. The real solution is to use the AD profile like Microsoft tells everyone to do.
So static logon scripts can be hard to maintain if you have a large amount of logic that are in them because if you change the name of a group somewhere and things like that. This can be made easier if you deploy your log in hooks with policy though. That way you don't have to actually go touch every computer. You just update it in your directory services.
You can go download this script now. It's on afp548.com. And that way you can take a look at it yourself. It's very simple. I wrote it in Bash and it's just--it's very simple to understand and easy to look at. So go ahead and go grab it and take a look and you can possibly use that or just even use it as kind of a template for working with log in scripts on your own. So hand things back to Joel now. Thank you very much.