I can’t believe it’s already been over 2 years since I started this blog and I still don’t post nearly as often as I’d like. I wish I could have something useful to post every week but, alas, I do not. I’m not even sure how much my blog gets seen (by real people) let alone is useful. Not many comments or feedback and I believe most of the visitors are just robots 🙁 Not being popular isn’t a biggie for me. The point of this blog was to help folks and I hope that I’m accomplishing that. To those that have posted comments, thank you! I’m always happy to know my efforts are not wasted or in vain. I also realized that when I switched from my custom theme to one I downloaded from WordPress it didn’t have my stats code so I dont have stats for the past few months :\ I flipped back to my old, custom theme, and will just have to deal with the poorly designed comments section… sorry folks.
Even though I’ve been busy and when I come home I don’t feel like working more, I’ve managed to get a few “quick drafts” saved of the items I want to post about. Some of those are:
Several months ago I bought an Arduino kit but have just gone through the simple projects in the book that came with it. Electronics have always fascinated me and I really want to get into some real projects. I have a co-worker that is really into this stuff and even designs and prints his own circuit boards. He’s given me a ton information, I just need to make the time to sit and do it. I know I’ll love that discovery process and writing about it.
Just can’t seem to find my motivation for much these days… can’t even remember the last time I was at the gym :\
Had a need to write a re-usable function at work to compare version numbers so that an action could be taken accordingly. It’s pretty simple but thought I’d share it anyway.
Function verCompare($ver1, $ver2) { # returns whether ver1 is Less, Greater, or Equal to ver2 $ver1Array = $ver1.Split(".") $ver2Array = $ver2.Split(".") # Decide which array has the least amount of subversions and we'll only compare the least amount If ($ver1Array.count -ge $ver2Array.count) { $count = $ver1Array.count } Else { $count = $ver2Array.count } # Loop through each sub version and compare them. # Once I hit a Greater or Less than I change the count to break # Out of the for loop because there is no need to compare further For ($i=0; $i -lt $count; $i++) { Switch ( $ver1Array[$i].CompareTo($ver2Array[$i]) ) { -1 { $compare = "Less"; $i = $count + 1 } 0 { $compare = "Equal" } 1 { $compare = "Greater"; $i = $count + 1 } } } return $compare }
What I’m doing here is accepting two versions. This function will tell you, in the end, if ver1 is greater than, equal to, or less than ver2. First I split each one using the “.” and store the array. I do this because, obviously, a number with multiple “.’s” isn’t really a number so you have to break them up and compare them separately.
Next I decide which one is the longer version number, for example 8.0.7601.3572 vs 8.1.7601. The second one has the least amount of subversions so I would only compare the first 3 version numbers instead of 4. Why? Well, to be honest, if you are using this function you’re 99% of the time going to be comparing versions of the same software and the number of subversions will probably be the same. I know this wont be true 100% of the time but lets go with it. In the event that the first 3 subversions are equal but one has an addition .### will you really know whether it’s greater, equal, or less than the other version had it been showing a subversion? Who knows. It would be simple enough to take this into consideration but I didn’t need to.
Next is just a for loop using a counter that counts up to the lowest number of subversions and uses that counter as the index to the array that holds the subversions for each version. It compares them using the built-in .CompareTo() method for [ints] and you can see in the switch what value that method returns depending on the result. I break out of the loop unless they are equal because there is no need to compare further once you already hit a value that is greater or equal. Using the numbers above this function would compare the first “8’s” and see they are equal, the move onto the next one which is 0 for ver1 and 1 for ver2. The loop would see ver2 is greater and then not bother to continue comparing the 7601 to 7601 because there is no need.
Once you return that value you can easily use it to act upon, such as we did below:
Function checkRegValue() { # Establish a minimum and maximum value that we # want the range to fall in, to act upon $minValue = "8.0.7601.15526" $maxValue = "9.11" # Get the current version installed $version = (get-itemproperty -Path "Registry::HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Internet Explorer\").Version # Use our compare function to see how the current # version compares to the min and max $minCompare = verCompare $version $minValue $maxCompare = verCompare $version $maxValue # To see if it is or falls between the min or max # values we want to know if it's NOT less than the # min value and NOT greater than the max value If ( ($minCompare -ne "Less") -and ($maxCompare -ne "Greater") ) { return 1 } Else { return 0 } }
And there you have it…
As part of my slow-moving efforts within my company to get WinRM enabled across the enterprise (14,000 computers…) I’ve had to do a bit of testing to make sure I can properly secure it. Much of that testing is around setting the execution level and making sure nothing outside of what I or my team has signed is able to be executed. To do that, I needed to be able to make my own, self-signed certs to test what it would be like with scripts coming from outside. Naturally, I chose OpenSSL I don’t have access to create Microsoft certs with our company tools and I don’t want to bug (or wait on) someone else to make them for me when I need them. I’m not patient like that. So, in typical geek fashion I set out to figure out how to do it on my own.
First I’ll start of by saying that 99% of what you find on the internet on how to do it will not work on Windows. Those instructions will work beautifully on Linux but if the instructions only tell you to make modifications to the config file, then those instructions are not for you. I went through several different sites giving values to set inside the config but it never worked. Every cert I ended up with was not valid for code signing! I ended up spending time going through the official OpenSSL documention and figuring out the method I ended up with. It’s not hard, it just uses a method most don’t know about or haven’t had a need to use. You’ll have to make changes to your main config file, create a supplemental one, and I throw in a batch file to automate it. I am using OpenSSL 1.0.1e that was released on 11 Feb 2013 on a Windows 7 machine.
Make sure the v3_req section in your openssl.cfg matches the one below:
[ v3_req ] # Extensions to add to a certificate request subjectKeyIdentifier=hash basicConstraints = CA:FALSE keyUsage = digitalSignature extendedKeyUsage = codeSigning, msCodeInd, msCodeCom nsCertType = client, email, objsign
You can take away the email under nsCertType but there isn’t a reason to. You can also add any additional types you may want this cert to do, just don’t take anything away that has Code, Signature or obj references in them.
You then want to create a NEW .cfg file and put the exact same properties as above (without the [ v3_req ] header). You can call it anything you want, just save it somewhere logical. I keep mine in the OpenSSL directory with the openssl.cfg.
Below is the batch script I wrote to automate the process of creating a new self-signed CA and a code signing cert.
REM Switch to the directory where openssl.exe is CD C:\OpenSSL-Win32\bin REM Create the key for the Certificate Authority. 2048 is the bit encryptiong, you can set it whatever you want openssl genrsa -out C:\YOURPATH\ca.key 2048 REM Next create the certificate and self-sign it (what the -new and -x509 do). Note, I'm explicitly telling it the main config path. You have to. openssl req -config C:\OpenSSL-Win32\bin\openssl.cfg -new -x509 -days 1826 -key C:\YOURPATH\ca.key -out C:\YOURPATH\ca.crt REM Now I'm creating the private key that will be for the actual code signing cert openssl genrsa -out C:\YOURPATH\codesign.key 2048 REM Creating the request for a certificate here. Note the -reqexts you need to tell it to pull that section from the main config or it wont do it. openssl req -config C:\OpenSSL-Win32\bin\openssl.cfg -new -key C:\YOURPATH\codesign.key -reqexts v3_req -out C:\YOURPATH\codesign.csr REM Signing the code signing cert with the certificate authority I created. Note the -extfile this is where you point to the new .cfg you made. openssl x509 -req -days 1826 -in C:\YOURPATH\codesign.csr -CA C:\YOURPATH\ca.crt -CAkey C:\YOURPATH\ca.key -extfile C:\OpenSSL-Win32\bin\v3.cfg -set_serial 01 -out C:\YOURPATH\codesign.crt REM Now I"m expoorting my key and crt into a PKCS12 (.pfx file) so that I can import it onto the machine that I'm going to use it to sign on. openssl pkcs12 -export -out C:\YOURPATH\codesign.pfx -inkey C:\YOURPATH\codesign.key -in C:\YOURPATH\codesign.crt
I know some of it looks redundant, and it is, but I found it all to be necessary to get it to work. I suspect it’s a bug with the Windows version of SSL since it should read it all from the openssl.cfg file. It does on Linux. I may have missed a specific scenario of testing config information in places, and maybe you can leave it out in one place, but this isn’t a long or complicated process so I see no reason to go back and fully verify.
I don’t go into detail on all of the parameters that are used. I don’t understand enough to do that (although I’m pretty sure I have it figured out) and I am by no means an expert on encryption or SSL. I hope this all works for you. If anyone has any website they recommend that gives a great, clear, and thorough explanation of how encryption (or specifically SSL) works I would really appreciate you linking it in the comments!
A few more notes:
A little while ago I had a dilemma brought to me at work from an application team. One of the tings we have fought using the Dragon Naturally Speaking application is the loss of data or profile corruption due to the application not being properly shut down.
The solution provided to us by a third party vendor was bloated and seemed much more complex than it needed to be. An AutoIT script was written by someone in my company to use the files provided by the vendor. It was the AutoIT script that called a batch file, which called cscript to run a vbs file (which did the saving), then went back to the AutoIT to call a com file which called an executable (created by one of the vendors) to close Dragon. Did you get lost? I was for a while trying to figure out what the scripts were doing and why.
It’s a simple process and the execution should be simple as well (although in IT that is often not the case). So, I set out to find a way to do it. Upon inspecting the COM I noticed it pointed to DragonCloser.exe which appeared to be a custom executable that the third party vendor wrote (or maybe Nuance did…). So, there must be an API to use. I looked it up and found an SDK online but I was hesitant to use it because one of my goals was not to have to push additional files to all of the PC’s that use Dragon. I also didn’t want to modify the scripted package I wrote to install Dragon.
After taking another look at the VBS script I noticed it was creating an object without ever loading an assembly or any library of any sort. This was the clue I needed to know that all I really needed was already loaded on the PC’s. I dove into the Program Files directory and found Interop.DNSTools.dll. Interop obviously standing for Interoperability and that was exactly what I was looking to do. I opened up the library in visual studio and browsed for the function I found in the VBS script. Now I knew what I needed to do.
The resulting Powershell script is only 7 lines. You can view/download it here: SaveAndCloseDragon
It’s fully commented and shouldn’t be too hard to follow. I hope this helps anyone looking to solve this issue. You can set it as a logoff script on any computer running Windows Vista or higher. I’m not sure if XP can do Powershell scripts or if installing Powershell adds that functionality to the logoff scripts area.
Wow, it’s been 5 months since I posted here! A lot has been going on with work, I took a real vacation, and I’m not so single anymore. I definitely have a ton of material to blog about, especially in the Powershell realm (go figure…). Like the script I wrote that will do subnet discovery (IP, PC name, logged in user) with just the input of a single PC. I’ve also been meaning to post stuff I wrote much longer ago like how I do my logging, how I put everything together in a single console, and maybe even a fun one: “How to send a speech message to another Windows 7 machine :).” I feel a little bad though… I haven’t touched PS much at all the past few months due to projects at work not leaving me time to play with it as much since they have me going into other realms like Citrix.
Today, I’m going to talk about a little PHP I wrote from scratch to dynamically create a photo gallery on a web page. I’m building one for my photography and I want the site to be LOW MAINTENANCE! This means no having to jump into code every time I want to add something or update it. The only other time I’ve dabbled in PHP is when I created this blog’s theme from absolute scratch. The code for the image gallery is simple, and I’m sure I could have googled for some code, but I would be much of a Curious Geek if I didn’t try and figure it out on my own. Since I’m not really a PHP programmer and I don’t know much, I just googled on how to do specific tasks like “PHP list directory” or “PHP dynamically insert html into page.” Found the functions I needed pretty quick and as a result I have this:
<?php $dirlist = scandir('./Portraits'); ?>
This is the third line of code, below the DOCTYPE and my PHP include (my header for all of my pages). This is the line of code that actually scans a given directory (In this case, the directory “Portraits” inside the same directory as the php page itself, they both are in the root). If I were putting the PHP file in the same directory as the photos, it would just be a “.”. The end of that sentence looks weird…. I assign it to the variable $dirlist so I can reference it later when I’m actually inserting the html.
I guess I should explain the layout of my gallery. I have the main photo being viewed on the left, and the thumbnails of all the images in the directory on the right of that. My rows are only 3 thumbnails wide. I use CSS to set the sizes and layout, which I wont get into here.
Next, we have:
<div class="photoBox" id="photo1"> <img id="displayImage" src="./Portraits/<?php echo $dirlist[2] ?>"> <div id="displayCaption" class="caption captionFade"></div> </div>
This is the div that contains the displayed photo. The only thing I really want to note here is the insertion of php code into the img src URL. I want it to start out displaying the first image it finds (the first two values in the array are . and ..).
Now here is the code doing the brunt of the work:
<div class="thumbContainer"> <?php foreach ($dirlist as $imgname) { If ($imgname !== "." and $imgname !== ".." and strpos($imgname, 'txt') == false) { $filename = substr_replace($manipulate, "txt", -3, 3); $filepath = './Portraits/' . $filename; If (file_exists($filepath)) { $innerHTML = file_get_contents($filepath); } Else { $innerHTML = " "; } $htmlString = '<div class="thumb"><img src="./Portraits/' . $imgname . '" onmousedown="document.getElementById(\'displayImage\').src=\'./Portraits/' . $imgname . '\'; displayCaption.innerHTML=\'' . $innerHTML . '\'"></div>'; echo $htmlString; } } ?> </div>
This is the container for the thumbnails, where the end-user clicks images to dynamically change the page.
Pretty simple stuff I think. It didn’t take me long to write it (if you subtract the time it took me to get quotes and php syntax all fixed…). This way, when I want to add an image and optionally a caption all I have to do is use FTP to upload them to the proper directory… AND THAT’S IT!! No having to jump into code for every little update!
Thanks to the official PHP 5 manual for telling me how to use a couple functions 🙂
EDIT: This is my old, kludgey way of doing it. Please see this new post: Remotely Enabling WinRM – Improved!
*********************
This post is going to build off of the technique I used in my previous post. My company only recently deployed Powershell to all of our XP devices. But neither the XP nor Windows 7 have WinRM enabled by default. This limits me so I had to seek a way to enable it on the fly. In the past when I’ve needed to run commands that weren’t “remote-friendly” in Powershell I had to create a scheduled task on the PC to run a batch script. I figured that was the way I’d need to go with this so I set out to do it. The tricky part was getting Powershell to run elevated on the Win 7 machines, running as System does not necessarily do that. With the help of the last post’s discovery I was able to accomplish it, though. Now I can remotely gather data without interfering with the user! They say the perfect IT guy is the one that accomplishes his work without the end-user even knowing what’s going on.
I’ve decided to just start attaching my completed script file to make it easier, and it’s commented so it should explain what I’m doing well enough. I’ve also thrown my info header at the top of the script so that maybe I can get some exposure if these things get passed around. This script requires that you have administrative rights on the remote machine!
In short, what it does is write .bat files to the PC, sets scheduled tasks to run them, runs them manually, and then deletes the .bat files and tasks.
I also want to note the reason I have -skipnetworkprofilecheck added to the bat file inside the script. This can raise a security concern since it’s going to enable the firewall rule for not only domain and private networks but also public! If I don’t do this, enable-psremoting will fail on some of our PC’s that run virtual environments such as VMWare (which my group, and some others, use for testing). The VMWare network adapter (and probably VirtualBox and others are like this) are set as public networks. If enable-psremoting detects a public network it will NOT do the enabling, even with the -force command. You’ll see later on in the .ps1 script where I modify the firewall rule to remove public networks.
Ok, here is the script: EnablePSRemoting
**I haven’t tested this actual script. The one I use at work is integrated into my console and some of the code in this is actually separate functions in my console. I’m pretty sure it works though 😉
I searched far and wide over the internet looking for an easy way to elevate powershell in a script whenever I needed to. The only solutions I ever found were practically a full page of code to look at this, and check that, then do this, jump through this hoop so it could do that… It had to be simpler than that! I didn’t even attempt to use their solutions because I refused to accept it’s complicated code.
It happens with start-process. The parameters are picky in how they are used but once you straighten it out in your head (or through many different trial and error iterations like myself) it’s not too bad. You can eleveate from within powershell, from a command prompt, or from a shortcut.
From Powershell:
start-process powershell.exe -verb runAs
Or if you want to run a command:
start-process powershell “get-process” -verb runAs
Anything passed in the quotes after the process name is passed as an argument to powershell (kind of like a script block)
You can also pass the path to a script as the argument.
From the Command Line
powershell.exe “start-process powershell -verb runAs”
Same thing as in powershell except you start a normal shell and execute a command to open an elevated shell right off the bat.
From a Shortcut
Your target should be: C:\path-to-powershell\powershell.exe “optional script file path” -verb runAs
And that’s all there is to it. Now, if you have UAC turned on you will be prompted. At work I don’t have this problem because we have a man-in-the-middle software that injects the token that allows the elevation without a UAC prompt.
Finally got tired of all the spam that shows up in my comments awaiting approval (all the activity I get, lol) so I implemented a plugin to to make sure the commenter is human.
Simple enough.
A couple of days after I made my last post I realized that, for that specific purpose, I could have just dynamically created hashtables as the values of each array. It would look like this pseudo-code:
$array = @() $array += @{ DriveLetter = $object.DriveLetter TotalSpace = $object.Size FreeSpace = $object.FreeSpace }
Just remember to first declare the array variable as an array or you’ll get errors. Then as I enumerate through each returned object it’s as simple as:
ForEach ($disk in $array) { write-host "Drive: $disk.DriveLetter has $disk.FreeSpace free space out of a total of $disk.TotalSpace" }
Or whatever I wanted to do with it. Now that I think about it, creating a specific name for each variable isn’t necessary and I can’t think of any scenarios where I really need to do that. I guess it could happen, though, so I’ll leave my previous post up.