I work mostly on Apple Mac OS X. I’ve also been writing a lot of Windows automation, and that means PowerShell DSC. PSDSC doesn’t work on OS X yet, and even once it does I won’t be able to test Windows-only resources. To test my configurations, I use Vagrant boxes. It took a little fiddling to get this set up, so I’m posting the code here in case you’re in the same situation.
This assumes you already have Vagrant working. I use the VirtualBox provider and I install everything with homebrew.
Today, Vagrant doesn’t have a native PowerShell DSC provisioner. I use the shell provisioner to run my simple headless PSDSC script, which compiles and runs a configuration. Follow that link and save a copy as
headless_dsc.ps1 and its XML file as
Next, copy this
Vagrantfile into the same directory:
Vagrant.configure("2") do |config| config.vm.box = "StefanScherer/windows_2019" config.vm.provision "file" do |file| file.source = "input.xml" file.destination = "input.xml" end config.vm.provision "shell" do |shell| shell.path = "headless_dsc.ps1" shell.args = ["-InputXmlFile", "input.xml"] # https://github.com/hashicorp/vagrant/issues/9138#issuecomment-444408251 shell.privileged = false end end
To create the box and run PSDSC:
If you’ve made changes and you want to recomplie and rerun the configuration:
- If you need to connect to the instance and run commands, check out
vagrant rdp. You’ll need to install Remote Desktop from the App Store. There’s a funky bug: if Remote Desktop isn’t open, the first
rdpcommand will open the app but won’t start a session. Just run it again and you’ll get a session window.
- The provisioner uploads the script and XML file on every run even though the current directory is mounted as a synced folder on the box by default. I could have used an inline shell script to call the script directly via that sync, but sometimes I disable the sync for testing and it’s convenient for the provisioner to keep working.
shell.privileged = false, I got errors like this:
default: (10,8):UserId: default: At line:72 char:1 default: + $folder.RegisterTaskDefinition($task_name, $task, 6, $username, $pass ... default: + ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ default: + CategoryInfo : OperationStopped: (:) , ArgumentException default: + FullyQualifiedErrorId : System.ArgumentException default: The system cannot find the file specified. (Exception from HRESULT: 0x80070002) default: At line:74 char:1 default: + $registered_task = $folder.GetTask("\$task_name") default: + ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ default: + CategoryInfo : OperationStopped: (:) , FileNotFoundException default: + FullyQualifiedErrorId : System.IO.FileNotFoundException default: You cannot call a method on a null-valued expression. default: At line:75 char:1 default: + $registered_task.Run($null) | Out-Null default: + ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ default: + CategoryInfo : InvalidOperation: (:) , RuntimeException default: + FullyQualifiedErrorId : InvokeMethodOnNull
The whole process froze and I had to ctrl+c twice to close it. There’s a bug. I left a link in a comment that I recommend you keep in your code so this setting isn’t confusing later.
Check out these related posts: