Posted
Comments None

This will be a quicky. If you want to save credentials for a PowerShell script, there are several methods you can use, but the one I prefer is to simply save a [System.Management.Automation.PSCredential] object using Export-CLIXML. This only works in PS version 3.0 and later. Toward the end I’ll detail a legacy PowerShell method.

First, open a PS Console session using the context that will be running the script. That means you are logging in as the account, on the system, where the credentials will be called. If you run it on AppSrv01 as AppSvc01, then log into AppSrv01 and right-click PowerShell and run it as AppSvc01.

In the console window, save the credential object, then export as CLI XML. (you’ll have to enter the user name and password after entering Get-Credential)

$Credential = Get-Credential
$Credential | Export-CLIXML [path-to-xml-file]

Piece of cake. Now, to recall that credential object, simply run

$Credential = Import-CLIXML [path-to-xml-file]

As long as the same account/computer is used to recall the credential object as the account that created it, you have a simple method for secure credential storage and retrieval. Now, if you only have access to PowerShell 2 (soon to be deprecated), you might be aware that Import-CLIXML/Export/CLIXML aren’t available. There are several methods for getting around this, but the method I prefer is systematic and straightforward.

$Credential = Get-Credential
$Credential.Password | ConvertFrom-SecureString | Set-Content [path-to-encrypted-password-file]

Note that for convenience, I prefer to save the encrypted password as the username.pass. So, in the example above, the filename would be “AppSvc01.pass”. To retrieve the password:

$Credential = New-Object System.Management.Automation.PSCredential [username],(Get-Content [path-to-encrypted-password-file] | ConvertTo-SecureString)

See? That’s all pretty straightforward and makes it pretty trivial to, at the very least, keep from storing your credentials in plain text. That said, here’s one final helpful/cautionary note about PSCredential objects. The password of a credential object in memory is trivially converted to plaintext, which means it is exactly as secure as the context under which it is stored.

$Credential.GetNetworkCredential().Password

Author

Posted
Comments None

If you have much of an interest in security, you likely have heard of Troy Hunt’s invaluable work over at Have I been Pwned? Some years back, he started collecting credential dumps from sources like pastebin and elsewhere, and building up his own database of compromised credentials. This allows anybody to enter an email address and discovery what breaches that address appears in. Someone could then take steps as necessary to change passwords, and hopefully be cured forever from password reuse.

You can also search for the presence a password, apart from the user ID, to see if the password is likely to be used in a dictionary attack. “Ah,” you say, “but then I’m providing my password to this site, which sounds like a bad idea,” (it is). HIBP provides several layers of security to make this process safer.

First, you may provide the SHA-1 hash of the password rather than the plain text. In so doing, if HIBP doesn’t have the password, then you are only providing the hash and not the source string. But what if you don’t even want to provide the hash, since an attacker that obtains the hash will have a much easier time performing dictionary and permutation attacks on your account?

Troy thought of that. You can now elect to provide just the first five characters of the hash, and the API will return the remainder of all hashes matching the substring. You can then perform a definitive check on the client side, without revealing the full hash to the server. For instance, the SHA-1 for “password” is “5baa61e4c9b93f3f0682250b6cf8331b7ee68fd8”. If we query the api with just the first five letters, “5baa6,” then it will return 466 matching hashes in the database, along with the number of times they appear. If you want to verify this, paste the following link into your browser

https://api.pwnedpasswords.com/range/5baa6

This provides any eavesdroppers almost no useful information, since there is no guarantee the password being checked appears in the list. Consider that “KEB49bet” and “HGNX1hyB” share the same first five letters in their hashes.

I wrote a couple functions in PowerShell to make it easy to call this API. The first is a simple function to return the hash of a string. Since this is a necessary part of the API call, it makes sense to make it a separate function. The second accepts a plaintext or securestring password and queries the HIBP database, returning if the password appears, and how many times.

Usage is straightforward:

Get-MDTPasswordBreachStatus -PlainTextPassword "password" -Force
Index Pwned   Count Hash
----- -----   ----- ----
    0  True 3303003 5baa61e4c9b93f3f0682250b6cf8331b7ee68fd8

For fun, see if you can figure out how to identify more strings whose hashes collide on just the first five letters.

Author

Posted
Comments None

I remember when I first started using SCCM about four or five years ago, I was delighted to learn there was a built-in PowerShell module. But then the more I used it the more it left me wanting. It seemed that each time I searched for solutions to common tasks, most of them relied on WMI queries and didn’t even bother with the first-party module.

This would frustrate me to no end, as there was this massive first-party module available to admins, but all these scripts and functions people provided that boiled down to figuring out the best WQL queries (a simplified SQL syntax). Well, I’ve come around on my thinking on this for several reasons.

First, my initial hesitance was largely based on my past experiences using Get-WMIObject and Get-CIMInstance: it’s often really, really slow. When writing deployments with the App Deployment Toolkit, I would run Get-WMIObject Win32_Application and then lock my screen and go get a cup of tea. (Side note: the ADTK has a built-in function that looks in the registry which is much faster and more convenient.) But, as it turns out, WMI queries against SCCM are pretty fast, even if you’re pulling large sets. In fact, I need to search further, but I would not be surprised if the ConfigurationManager module itself heavily relies on WMI.

Second, I was just really annoyed that people were ignoring a perfectly good module that everybody has. This was my own lack of experience with working in enterprise IT. SCCM 2007 had no PowerShell support, and 2012 didn’t receive it until SP1. Since then, in current branch, the support has only been better. But… most admins don’t have the luxury of updating to the latest branch every time they feel like it. Changes come slowly, especially if everything currently works. We as admins always want to lay the foundation for a brighter, easier to administrate future, but there’s this thing called change management. The nice thing about the WMI scripts and utilities people have written is they tend to be pretty backward compatible, versus relying on CMDlets or features only available since, say, 1710.

Third, and finally, I didn’t realize that even hundreds of first-party CMDlets aren’t going to cover all of the bases. There are a lot of edge cases, that may be commonplace for some environments, that the official module can’t fully support. For instance, if you need to know the distribution status of all of the references for a task sequence, that’s going to require looking beyond the official module.

Once I got past these prejudices, as so often happens, I learned a lot about both WMI and SCCM, and gained competencies I probably wouldn’t have previously. And to be honest, that’s the most satisfying work for the scripting administrator, isn’t it? Work done; knowledge acquired.

Author

Posted
Comments None

PowerShell 6 finally made it out of Beta two weeks ago. That is cause for celebration, as there are a lot of quality of life improvements for those of us who work all day in the shell. But it’s… not what you think if you have not been following the team blogs or at least perusing tech news the last year or so.

PowerShell 5 and the versions before it are based on the .NET Framework. You know, those giant packages that Windows developers love because they’re so easy to work with and end users and administrators tolerate, since it occasionally means having to update something else in addition to the software we are trying to run. Version 6, on the other hand, is based on .NET Core 2.0.

That means PowerShell 6 is open source, cross-platform— hello, PowerShell on a Raspberry Pi 3 —and part of Microsoft’s recent and radical trend toward cloud-first, open source friendly business. The bad news is that it does not support some existing modules, chiefly, Active Directory. The good news is that you can run 6 and your current version side-by-side and that Microsoft will probably be supporting version 5 for years to come, but… man, I hope they fix that bad news.

Author

Posted
Comments None

For day in and day out administration, we should engage in best practices and encourage our colleagues to do the same. Write scripts for longevity and legibility; comment thorougly; test, test, and test again. Sometimes, though, we just need a snippet of PowerShell to live fast and die young.*

Recently at work I was faced with a challenge: our technicians were going to be going to a few dozen computers, logging in locally, and performing some specific steps. We developed a process and accompanying documentation for them, but because they were authenticating locally, there would be no easy access to Domain-gated resources, including a soft copy of the documentation itself (for copy-paste). The solution seemed to be a to put the instructions on a temporary webserver with anonymous auth, and then blow it away at the conclusion of the maintenance.

IIS would work fine for this, but I had so far not had a reason to install IIS on the 2012 server that hosts my customized reports and other scheduled tasks and, besides, that would not be much fun. PowerShell and easy access to .NET classes to the rescue!

The core of the disposable webserver is the .NET [HttpListener] class. The only real “innovation” my script offers over similar online examples is that it utilizes the “GetContextAsync()” method, versus the typical “GetContext().” This lets us easily start and stop the service interactively, so we can inspect any of the objects at will. This can be a fun way to learn both about PowerShell and web services.

To learn the most from it, I suggest creating a simple index.html file in the same location as the script, and firing it up in the PowerShell ISE (as admin—it will not work othewise). At any point, hit CTRL-C or the ISE stop button to stop the server and interact with the objects the script has created. Note that you will need to stop the listener by executing the following in the shell before you can restart the script.

$listener.Stop()

For some fun, try changing the authentication to NTLM or Negotiate and see how that changes the $context variable. This can be a very practical way to learn about claims and tokens. Add a query in the URL when you make the request. Try returning JSON formatted data and consuming it from PowerShell with Invoke-RESTMethod. Try Posting data.

Just make sure you close the console window when you’re done because, after all, we’re Adminning Dangerously.

*The author does not admin dangerously. The author wishes to express that this is a figure of speech and there are many more dangerous things people regularly do than this simple, temporary script that provides read-only information. The author does not condone any actual dangerous adminning that readers of this article may undertake.

Author

← Older Newer →