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 Headless PSDSC script, which compiles and runs a configuration:
Param( [Parameter(Mandatory=$false)] [String[]] $InputXmlFile ) if ($InputXmlFile) { [XML]$Inputs = Get-Content -Path $InputXmlFile } $NodeData = @{ NodeName = "localhost" Message = "This was hardcoded in the node data." Inputs = $Inputs.inputs } $ConfigurationData = @{AllNodes = @($NodeData)} Configuration Headless { Import-DscResource -ModuleName PSDesiredStateConfiguration Node 'localhost' { Log Message { Message = $AllNodes.Message } if ($AllNodes.Inputs) { Log Input { Message = $AllNodes.Inputs.Message } } } } Headless -ConfigurationData $ConfigurationData Start-DscConfiguration -Wait -Force -Verbose -Path .\Headless\
And here’s an input file to provide the example messages:
<Inputs> <Message>This message came from the XML inputs.</Message> </Inputs>
Now all you need is a Vagrantfile
in 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:
vagrant up
If you’ve made changes and you want to recomplie and rerun the configuration:
vagrant provision
Notes:
- 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 firstrdp
command 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.
- Without
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 in the
Vagrantfile
that I recommend you keep in your code so this setting isn’t confusing later.
Happy automating!
Adam
Need more than just this article? We’re available to consult.
You might also want to check out these related articles: