Tiny Deathstars of Foulness

Simple request: Search for all files in a directory and the child directories for a specific pattern and then return the filename without the path to the file. There are a few commandlets we end up needing to use:

  • Get-ChildItem: Creates a recursive array of filenames and pipes that output into the For loop.
  • ForEach-Object: Starts a for loop, looping through the output of the command that has been piped into the loop (much easier than an IFS array IMHO).
  • If: This starts the if pattern that ends after the select-string in the below command, but only dumps the $_.PSPath if the pattern is true.
  • Select-String: Searches for the content in the file.
  • Split-Path: This is the Powershell equivalent of basename and dirname. You can use this commandlet to extract parts of the path to a file. In this case, we’ll use the -Leaf option which effectively runs the basename, or just the file name in the path to a file.

Get-ChildItem -include * -recurse | ForEach-Object { if( ( $(Get-Content $_) | select-string -pattern "Finished processing mailbox") ) { $_.PSPath }} | Split-Path -Leaf

You can also search for the files that specifically don’t have that given pattern included in them instead by adding a ! in front of the Get-Content:

Get-ChildItem -include * -recurse | ForEach-Object { if( !( $(Get-Content $_) | select-string -pattern "Finished processing mailbox") ) { $_.PSPath }} | Split-Path -Leaf

Note: This runs recursively from the existing working directory (and yes, you can use pwd to return a path, just like the bash built-in).

Finally, the > operator can then be placed into the end to dump our data to a file:

Get-ChildItem -include * -recurse | ForEach-Object { if( !( $(Get-Content $_) | select-string -pattern "Finished processing mailbox") ) { $_.PSPath }} | Split-Path -Leaf > Complete.txt


April 18th, 2014

Posted In: Active Directory, Microsoft Exchange Server, Windows Server

Tags: , , , , , , , , , , ,

In a previous post I looked at automating iPhone and iPad deployment. There, we looked at the iPhone Configuration Utility. Now that Profile Manager is built into Mac OS X Server in Lion, and with the number of 3rd party MDM solutions on the market, many users of iPhone Configuration Utility are looking to extract information from it and move it into other places. Many of these places can import property lists.

If you look at the file header for .mobileconfig and .deviceinfo files you’ll notice that they begin with the familiar:

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "">
<plist version="1.0"><dict>

Given that .mobileconfig and .deviceinfo files are property lists with different extensions, if you want to turn them into property lists, simply rename them. Given that many people will have 100s or 1000s of devices, this is something that most will want to automate. So, let’s use a basic for loop to do so. The following will convert .mobileconfig files into plist:

for x in ~/Library/MobileDevice/Configuration Profiles/*.mobileconfig; do mv $x `basename $x .mobileconfig`.plist; done;

This will put them back:

for x in ~/Library/MobileDevice/Configuration Profiles/*.plist; do mv $x `basename $x .plist`.mobileconfig; done;

Or to convert the device information to property lists:

for x in ~/Library/MobileDevice/Devices/*.deviceinfo; do mv $x `basename $x .deviceinfo`.plist; done;

Or property lists to device information:

for x in ~/Library/MobileDevice/Devices/*.plist; do mv $x `basename $x .plist`.deviceinfo; done;

Once files are converted then you can also automate crawling through them to obtain information. For example, to pull the information from the two fields in iPhone Configuration Utility that are user editable, ownerName and ownerEmail as well as the serial number of a device with a deviceIdentifier of 26c2d1b2a68c7862bd4c6bfbe708517964733cf3:

defaults read ~/Library/MobileDevice/Devices/26c2d1b2a68c7862bd4c6bfbe708517964733cf3 ownerEmail

defaults read ~/Library/MobileDevice/Devices/26c2d1b2a68c7862bd4c6bfbe708517964733cf3 ownerName

You could then redirect this output into a csv file, perhaps grabbing other information such as:

  • UniqueChipID
  • deviceActivationState
  • deviceBluetoothMACAddress
  • deviceBuildVersion
  • deviceCapacityKey
  • deviceClass
  • deviceIdentifier (also the basename of the file)
  • deviceLastConnected
  • deviceName
  • deviceProductVersion
  • deviceType
  • deviceWiFiMACAddress

And then there are 3 arrays that wouldn’t likely look great in a csv, but could easily be brought out automatically:

  • provisioningProfiles: useful if you are duplicating provisioning profile information into an mdm solution
  • configurationProfiles: useful if you are duplicating configuration profile information from devices into an mdm solution
  • applicationDictionaries: great for pulling off what apps are where

You can get all of this without moving the files to plist as well, but in this example I am making an assumption that you will be importing these devices via plist and so you would be converting them anyway. The ability to dump information into a csv for reporting or other types of imports is ancillary. Having said this, I’ve taken it all and wrapped it into a shell script:

echo deviceIdentifier,deviceSerialNumber,ownerName,ownerEmail,UniqueChipID,deviceActivationState,deviceBluetoothMACAddress,deviceBuildVersion,deviceCapacityKey,deviceClass,deviceLastConnected,deviceName,deviceProductVersion,deviceWiFiMACAddress,deviceType > ~/mydevices.csv
for deviceID in *.deviceinfo; do mv "$deviceID" "`basename "$deviceID" .deviceinfo`.plist";
deviceserialnumber=`defaults read ~/Library/MobileDevice/Devices/$deviceID deviceSerialNumber`
ownerName=`defaults read ~/Library/MobileDevice/Devices/$deviceID ownerName`
ownerEmail=`defaults read ~/Library/MobileDevice/Devices/$deviceID ownerEmail`
UniqueChipID=`defaults read ~/Library/MobileDevice/Devices/$deviceID UniqueChipID`
deviceActivationState=`defaults read ~/Library/MobileDevice/Devices/$deviceID deviceActivationState`
deviceBluetoothMACAddress=`defaults read ~/Library/MobileDevice/Devices/$deviceID deviceBluetoothMACAddress`
deviceBuildVersion=`defaults read ~/Library/MobileDevice/Devices/$deviceID deviceBuildVersion`
deviceCapacityKey=`defaults read ~/Library/MobileDevice/Devices/$deviceID deviceCapacityKey`
deviceClass=`defaults read ~/Library/MobileDevice/Devices/$deviceID deviceClass`
deviceLastConnected=`defaults read ~/Library/MobileDevice/Devices/$deviceID deviceLastConnected`
deviceName=`defaults read ~/Library/MobileDevice/Devices/$deviceID deviceName`
deviceProductVersion=`defaults read ~/Library/MobileDevice/Devices/$deviceID deviceProductVersion`
deviceType=`defaults read ~/Library/MobileDevice/Devices/$deviceID deviceType`
deviceWiFiMACAddress=`defaults read ~/Library/MobileDevice/Devices/$deviceID deviceWiFiMACAddress`
echo $deviceID,$deviceserialnumber,$ownerName,$ownerEmail,$UniqueChipID,$deviceActivationState,$deviceBluetoothMACAddress,$deviceBuildVersion,$deviceCapacityKey,$deviceClass,$deviceLastConnected,$deviceName,$deviceProductVersion,$deviceWiFiMACAddress,$deviceType >> ~/mydevices.csv

This script (which should have a bit more logic put into it for defining things, etc) should convert all of your .deviceinfo files to property list while building a csv of their contents (minus the arrays, which I didn’t think prudent to put into csv but which could be thrown in there pretty easily) in ~/mydevices.csv (or my devices.csv in your home directory). ProfileManager can definitely import device holders, which you should be able to do with a couple of columns of this output…

And to undo the conversion to plist (if you didn’t actually mean to do that part):

for x in ~/Library/MobileDevice/Devices/*.plist; do mv $x `basename $x .plist`.deviceinfo; done;

August 1st, 2011

Posted In: iPhone, Mac OS X, Mac OS X Server, Mac Security

Tags: , , , , , , , , , , ,